Me sorprendió encontrar hoy que no podía rastrear ninguna forma simple de escribir el contenido de una InputStream
a una OutputStream
en Java. Obviamente, el código de búfer de bytes no es difícil de escribir, pero sospecho que me falta algo que me facilitaría la vida (y el código más claro).
Entonces, dada una InputStream
in
y una OutputStream
out
, ¿hay una manera más simple de escribir lo siguiente?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Respuestas:
Java 9
Desde Java 9,
InputStream
proporciona un método llamadotransferTo
con la siguiente firma:Como lo indica la documentación
transferTo
:Entonces, para escribir el contenido de un Java
InputStream
en unOutputStream
, puede escribir:fuente
Files.copy
tanto como sea posible. Se implementa en código nativo y, por lo tanto, puede ser más rápido.transferTo
debe usarse solo si ambas secuencias no son FileInputStream / FileOutputStream.Files.copy
no maneja ninguna secuencia de entrada / salida, pero está específicamente diseñado para secuencias de archivos .Como mencionó WMR,
org.apache.commons.io.IOUtils
desde Apache tiene un método llamadocopy(InputStream,OutputStream)
que hace exactamente lo que estás buscando.Así que tienes:
... en tu código.
¿Hay alguna razón por la que estás evitando
IOUtils
?fuente
in
yout
debe cerrarse al final del código en un bloque finalmenteSi está utilizando Java 7, los archivos (en la biblioteca estándar) son el mejor enfoque:
Editar: Por supuesto, es útil cuando crea uno de InputStream o OutputStream desde el archivo. Use
file.toPath()
para obtener la ruta del archivo.Para escribir en un archivo existente (por ejemplo, uno creado con
File.createTempFile()
), deberá pasar laREPLACE_EXISTING
opción de copia (de lo contrario,FileAlreadyExistsException
se arroja):fuente
Files
NO está disponible en Java 1.7 de Android . Esto me picó: stackoverflow.com/questions/24869323/…Files.copy()
que toma dos flujos, y es lo que todas las demásFiles.copy()
funciones adelantan para hacer el trabajo real de copia. Sin embargo, es privado (ya que en realidad no involucra rutas o archivos en esa etapa), y se ve exactamente como el código en la propia pregunta del OP (más una declaración de devolución). Sin apertura, sin cierre, solo un bucle de copia.Creo que esto funcionará, pero asegúrese de probarlo ... una "mejora" menor, pero podría ser un poco costoso en la legibilidad.
fuente
while(len > 0)
lugar de!= -1
, porque este último también podría devolver 0 cuando se usa elread(byte b[], int off, int len)
método-, que arroja una excepción @out.write
InputStream
contrato de lectura para devolver 0 cualquier cantidad de veces. Y de acuerdo con elOutputStream
contrato, el método de escritura debe aceptar una longitud de 0 y solo debe arrojar una excepción cuandolen
sea negativo.while
afor
ay poniendo una de las variables en la sección de inicio de for: ejfor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)read()
solo puede devolver cero si proporcionó una longitud de cero, lo que sería un error de programación y una estúpida condición de bucle para siempre. Ywrite()
no , no lanzar una excepción si se proporciona una longitud cero.Usando guayaba
ByteStreams.copy()
:fuente
Files.copy
tanto como sea posible. UseByteStreams.copy
solo si ambas transmisiones no son FileInputStream / FileOutputStream.Función simple
Si solo necesita esto para escribir un
InputStream
a,File
entonces puede usar esta función simple:fuente
close()
llamadas enfinally
bloques?Los
JDK
utiliza el mismo código por lo que parece que no hay manera "fácil", sin bibliotecas torpe de terceros (que probablemente no hacer nada diferente de todos modos). Lo siguiente se copia directamente dejava.nio.file.Files.java
:fuente
PipedInputStream
yPipedOutputStream
solo debe usarse cuando tiene varios subprocesos, como lo señala el Javadoc .Además, tenga en cuenta que las secuencias de entrada y las secuencias de salida no envuelven las interrupciones de subprocesos con
IOException
s ... Por lo tanto, debe considerar incorporar una política de interrupción a su código:Esta sería una adición útil si espera utilizar esta API para copiar grandes volúmenes de datos o datos de secuencias que se atascan durante un tiempo intolerablemente largo.
fuente
Para aquellos que usan Spring Framework, hay una clase útil de StreamUtils :
Lo anterior no cierra las transmisiones. Si desea que las secuencias se cierren después de la copia, use la clase FileCopyUtils en su lugar:
fuente
No hay manera de hacer esto mucho más fácil con los métodos JDK, pero como Apocalisp ya lo ha notado, no eres el único con esta idea: podrías usar IOUtils de Jakarta Commons IO , también tiene muchas otras cosas útiles, que la OMI debería ser parte del JDK ...
fuente
Usando Java7 y prueba con recursos , viene con una versión simplificada y legible.
fuente
Aquí viene cómo lo estoy haciendo con el bucle más simple.
fuente
Use la clase Util de Commons Net:
fuente
Un fragmento de IMHO más mínimo (que también abarca de forma más estrecha la variable de longitud):
Como nota al margen, no entiendo por qué más personas no utilizan un
for
bucle, sino que optan por unawhile
expresión de asignación y prueba que algunos consideran un estilo "pobre".fuente
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
Esta es mi mejor oportunidad !!
Y no lo use
inputStream.transferTo(...)
porque es demasiado genérico. El rendimiento de su código será mejor si controla su memoria de búfer.Lo uso con este método (mejorable) cuando sé de antemano el tamaño de la transmisión.
fuente
Creo que es mejor usar un búfer grande, porque la mayoría de los archivos tienen más de 1024 bytes. También es una buena práctica verificar que el número de bytes leídos sea positivo.
fuente
Yo uso
BufferedInputStream
yBufferedOutputStream
para eliminar la semántica del búfer del códigofuente
PipedInputStream y PipedOutputStream pueden ser de alguna utilidad, ya que puede conectar uno con el otro.
fuente
Otro posible candidato son las utilidades de E / S de guayaba:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Pensé en usarlos, ya que Guava ya es inmensamente útil en mi proyecto, en lugar de agregar otra biblioteca para una función.
fuente
copy
ytoByteArray
métodos en docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (guava llama a las secuencias de entrada / salida como "secuencias de bytes" y lectores / escritores como "secuencias de caracteres")No es muy legible, pero efectivo, no tiene dependencias y se ejecuta con cualquier versión de Java
fuente
!= -1
o> 0
? Esos predicados no son exactamente lo mismo.fuente
Prueba Cactoos :
Más detalles aquí: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
fuente
puedes usar este método
fuente
catch(Exception ex){}
- esto es de primera categoría