txt texto por modificar manejo linea leer guardar escribir datos crear como archivos archivo java io stream

texto - Una forma sencilla de escribir contenidos de un Java InputStream en un OutputStream



manejo de archivos en java netbeans (20)

Me sorprendió descubrir que hoy no podía rastrear ninguna forma sencilla de escribir el contenido de un InputStream en un OutputStream en Java. Obviamente, el código del búfer de bytes no es difícil de escribir, pero sospecho que me estoy perdiendo algo que haría mi vida más fácil (y el código más claro).

Entonces, dada una entrada InputStream y una out OutputStream , ¿hay una forma más sencilla 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); }


Java 9

Desde Java 9, InputStream proporciona un método llamado transferTo con la siguiente firma:

public long transferTo(OutputStream out) throws IOException

Como indica la documentation , transferTo :

Lee todos los bytes de este flujo de entrada y escribe los bytes en el flujo de salida dado en el orden en que se leen. A cambio, esta secuencia de entrada estará al final de la secuencia. Este método no cierra ninguna de las secuencias.

Este método puede bloquear la lectura indefinida de la secuencia de entrada o escribir en la secuencia de salida. El comportamiento del caso en el que el flujo de entrada y / o salida se cierra de forma asíncrona, o el hilo interrumpido durante la transferencia, es altamente específico del flujo de entrada y salida, y por lo tanto no se especifica

Entonces, para escribir el contenido de un Java InputStream en un OutputStream , puede escribir:

input.transferTo(output);


Función simple

Si solo necesita esto para escribir un InputStream en un File , puede usar esta sencilla función:

private void copyInputStreamToFile( InputStream in, File file ) { try { OutputStream out = new FileOutputStream(file); byte[] buf = new byte[1024]; int len; while((len=in.read(buf))>0){ out.write(buf,0,len); } out.close(); in.close(); } catch (Exception e) { e.printStackTrace(); } }


Aquí viene cómo lo estoy haciendo con el bucle más simple.

private void copy(final InputStream in, final OutputStream out) throws IOException { final byte[] b = new byte[8192]; for (int r; (r = in.read(b)) != -1;) { out.write(b, 0, r); } }


Como mencionó WMR, org.apache.commons.io.IOUtils de Apache tiene un método llamado copy(InputStream,OutputStream) que hace exactamente lo que está buscando.

Así que tienes:

InputStream in; OutputStream out; IOUtils.copy(in,out); in.close(); out.close();

... en su código.

¿Hay alguna razón por la que estés evitando los IOUtils ?


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 de lectura sea positivo.

byte[] buffer = new byte[4096]; int n; while ((n = in.read(buffer)) > 0) { out.write(buffer, 0, n); } out.close();


Creo que esto funcionará, pero asegúrate de probarlo ... una "mejora" menor, pero podría ser un poco costoso para la legibilidad.

byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); }


El JDK usa el mismo código, por lo que parece que no hay una forma "más fácil" sin las bibliotecas de terceros (que probablemente no hagan nada diferente). Lo siguiente se copia directamente de java.nio.file.Files.java :

// buffer size used for reading and writing private static final int BUFFER_SIZE = 8192; /** * Reads all bytes from an input stream and writes them to an output stream. */ private static long copy(InputStream source, OutputStream sink) throws IOException { long nread = 0L; byte[] buf = new byte[BUFFER_SIZE]; int n; while ((n = source.read(buf)) > 0) { sink.write(buf, 0, n); nread += n; } return nread; }


El uso de Java7 y try-with-resources , viene con una versión simplificada y legible.

try(InputStream inputStream = new FileInputStream("C://mov.mp4"); OutputStream outputStream = new FileOutputStream("D://mov.mp4")){ byte[] buffer = new byte[10*1024]; for (int length; (length = inputStream.read(buffer)) != -1; ){ outputStream.write(buffer, 0, length); } }catch (FileNotFoundException exception){ exception.printStackTrace(); }catch (IOException ioException){ ioException.printStackTrace(); }


No hay manera de hacer esto mucho más fácil con los métodos JDK, pero como Apocalisp ya ha notado, no eres el único con esta idea: puedes usar IOUtils de Jakarta Commons IO , también tiene muchas otras cosas útiles, que la OMI debería ser parte del JDK ...



Para aquellos que usan Spring Framework hay una clase útil de StreamUtils :

StreamUtils.copy(in, out);

Lo anterior no cierra los arroyos. Si desea que las secuencias se cierren después de la copia, use la clase FileCopyUtils lugar:

FileCopyUtils.copy(in, out);


PipedInputStream y PipedOutputStream pueden ser de alguna utilidad, ya que puede conectarse entre sí.



Si está utilizando Java 7, Files (en la biblioteca estándar) es el mejor enfoque:

/* You can get Path from file also: file.toPath() */ Files.copy(InputStream in, Path target) Files.copy(Path source, OutputStream out)

Edición: por supuesto, es útil cuando crea uno de InputStream o OutputStream desde un 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 la opción de copia REPLACE_EXISTING (de lo contrario, se FileAlreadyExistsException ):

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)


Un fragmento más mínimo de IMHO (que también afecta más estrechamente la variable de longitud):

byte[] buffer = new byte[2048]; for (int n = in.read(buffer); n >= 0; n = in.read(buffer)) out.write(buffer, 0, n);

Como nota al margen, no entiendo por qué más personas no usan un bucle for , en lugar de optar por un while con una expresión de asignación y prueba que algunos consideran un estilo "pobre".



Use la clase Util de Commons Net:

import org.apache.commons.net.io.Util; ... Util.copyStream(in, out);


puedes usar este método

public static void copyStream(InputStream is, OutputStream os) { final int buffer_size=1024; try { byte[] bytes=new byte[buffer_size]; for(;;) { int count=is.read(bytes, 0, buffer_size); if(count==-1) break; os.write(bytes, 0, count); } } catch(Exception ex){} }


PipedInputStream y PipedOutputStream solo se deben usar cuando tienes varios subprocesos, como lo indica el Javadoc .

Además, tenga en cuenta que las secuencias de entrada y las de salida no envuelven ninguna interrupción de subprocesos con las IOException s ... Por lo tanto, debería considerar la incorporación de una política de interrupción a su código:

byte[] buffer = new byte[1024]; int len = in.read(buffer); while (len != -1) { out.write(buffer, 0, len); len = in.read(buffer); if (Thread.interrupted()) { throw new InterruptedException(); } }

Esto sería una adición útil si espera usar esta API para copiar grandes volúmenes de datos, o datos de flujos que se atascan durante un tiempo intolerablemente largo.


public static boolean copyFile(InputStream inputStream, OutputStream out) { byte buf[] = new byte[1024]; int len; long startTime=System.currentTimeMillis(); try { while ((len = inputStream.read(buf)) != -1) { out.write(buf, 0, len); } long endTime=System.currentTimeMillis()-startTime; Log.v("","Time taken to transfer all bytes is : "+endTime); out.close(); inputStream.close(); } catch (IOException e) { return false; } return true; }