Fiquei surpreso ao descobrir hoje que não consegui rastrear nenhuma maneira simples de escrever o conteúdo de um InputStream
para um OutputStream
em Java. Obviamente, o código do buffer de bytes não é difícil de escrever, mas suspeito que estou perdendo algo que tornaria minha vida mais fácil (e o código mais claro).
Então, dado um InputStream
in
e um OutputStream
out
, existe uma maneira mais simples de escrever o seguinte?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Respostas:
Java 9
Desde o Java 9,
InputStream
fornece um método chamadotransferTo
com a seguinte assinatura:Como declara a documentação ,
transferTo
irá:Portanto, para escrever o conteúdo de um Java
InputStream
em umOutputStream
, você pode escrever:fonte
Files.copy
o máximo possível. É implementado em código nativo e, portanto, pode ser mais rápido.transferTo
deve ser usado apenas se os dois fluxos não forem FileInputStream / FileOutputStream.Files.copy
, não lida com nenhum fluxo de entrada / saída, mas foi projetado especificamente para fluxos de arquivos .Como o WMR mencionou, o
org.apache.commons.io.IOUtils
Apache possui um método chamadocopy(InputStream,OutputStream)
que faz exatamente o que você está procurando.Então você tem:
... no seu código.
Existe uma razão para você estar evitando
IOUtils
?fonte
in
eout
deve ser fechado no final do código em um bloco finallySe você estiver usando o Java 7, o Files (na biblioteca padrão) é a melhor abordagem:
Editar: claro que é apenas útil quando você cria um de InputStream ou OutputStream a partir do arquivo. Usar
file.toPath()
para obter o caminho do arquivo.Para gravar em um arquivo existente (por exemplo, um criado com
File.createTempFile()
), você precisará passar aREPLACE_EXISTING
opção de cópia (caso contrário,FileAlreadyExistsException
será lançada):fonte
Files
NÃO está disponível no Java 1.7 do Android . I got Picado por este: stackoverflow.com/questions/24869323/...Files.copy()
que recebe dois fluxos e é o que todas as outrasFiles.copy()
funções encaminham para realizar o trabalho real de cópia. No entanto, é privado (já que na verdade não envolve Caminhos ou Arquivos nesse estágio) e se parece exatamente com o código na pergunta do OP (além de uma declaração de retorno). Sem abertura, sem fechamento, apenas um loop de cópia.Eu acho que isso funcionará, mas certifique-se de testá-lo ... "pequenas melhorias", mas pode ser um pouco de custo na legibilidade.
fonte
while(len > 0)
, em vez de!= -1
, porque este último também pode retornar 0 ao usar oread(byte b[], int off, int len)
-method, que lança uma exceção @out.write
InputStream
contrato, que a leitura retorne 0 várias vezes. E de acordo com oOutputStream
contrato, o método de gravação deve aceitar um comprimento de 0 e só deve lançar uma exceção quandolen
for negativo.while
para afor
e colocando uma das variáveis na seção init do for: por exemplofor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
,. =)read()
só pode retornar zero se você tiver fornecido um comprimento igual a zero, o que seria um erro de programação e uma condição estúpida para repetir para sempre. Ewrite()
se não lançar uma exceção se você fornecer um comprimento zero.Usando goiabas
ByteStreams.copy()
:fonte
Files.copy
o máximo possível. UseByteStreams.copy
apenas se os dois fluxos não forem FileInputStream / FileOutputStream.Função Simples
Se você só precisa disso para escrever um
InputStream
para umFile
, pode usar esta função simples:fonte
close()
chamadas emfinally
blocos?Ele
JDK
usa o mesmo código, então parece que não há uma maneira "mais fácil" sem bibliotecas desajeitadas de terceiros (que provavelmente não fazem nada diferente de qualquer maneira). O seguinte é copiado diretamente dejava.nio.file.Files.java
:fonte
PipedInputStream
ePipedOutputStream
só deve ser usado quando você possui vários encadeamentos, conforme observado pelo Javadoc .Além disso, observe que os fluxos de entrada e de saída não envolvem nenhuma interrupção de encadeamento com
IOException
s ... Portanto, considere incorporar uma política de interrupção ao seu código:Isso seria uma adição útil se você espera usar essa API para copiar grandes volumes de dados ou dados de fluxos que ficam presos por um tempo intoleravelmente longo.
fonte
Para quem usa o framework Spring, existe uma classe StreamUtils útil :
O acima não fecha os fluxos. Se você deseja que os fluxos sejam fechados após a cópia, use a classe FileCopyUtils :
fonte
Não há como fazer isso muito mais facilmente com os métodos JDK, mas como o Apocalisp já observou, você não é o único com essa ideia: você pode usar IOUtils do Jakarta Commons IO , mas também tem muitas outras coisas úteis, que a IMO deveria realmente fazer parte do JDK ...
fonte
Usando Java7 e try-with-resources , vem com uma versão simplificada e legível.
fonte
Aí vem como estou indo com o loop for mais simples.
fonte
Use a classe Util da Commons Net:
fonte
Um trecho mais mínimo da IMHO (que também escopo mais estreitamente a variável length):
Como uma observação lateral, não entendo por que mais pessoas não usam um
for
loop, em vez disso, optam por umawhile
com uma expressão de atribuição e teste que é considerada por alguns como estilo "ruim".fonte
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Esta é a minha melhor chance !!
E não use
inputStream.transferTo(...)
porque é muito genérico. O desempenho do seu código será melhor se você controlar sua memória buffer.Eu o uso com esse método (improvável) quando conheço antecipadamente o tamanho do fluxo.
fonte
Eu acho que é melhor usar um buffer grande, porque a maioria dos arquivos tem mais de 1024 bytes. Também é uma boa prática verificar se o número de bytes de leitura é positivo.
fonte
Eu uso
BufferedInputStream
eBufferedOutputStream
para remover a semântica de buffer do códigofonte
PipedInputStream e PipedOutputStream podem ser de alguma utilidade, pois você pode conectar um ao outro.
fonte
Outro candidato possível são os utilitários de E / S do Guava:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Eu pensei em usá-los, pois o Guava já é imensamente útil no meu projeto, em vez de adicionar mais uma biblioteca para uma função.
fonte
copy
etoByteArray
métodos em docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (a goiaba chama fluxos de entrada / saída como "fluxos de bytes" e leitores /Não é muito legível, mas eficaz, não possui dependências e é executado com qualquer versão java
fonte
!= -1
ou> 0
? Esses predicados não são exatamente os mesmos.fonte
Experimente o Cactoos :
Mais detalhes aqui: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
fonte
você pode usar esse método
fonte
catch(Exception ex){}
- this is top-notch #