简单的方法将Java InputStream的内容写入OutputStream

今天我惊讶地发现,我无法find任何简单的方法来将InputStream的内容写入到Java中的OutputStream中。 显然,字节缓冲区的代码不难写,但是我怀疑我只是错过了一些能让我的生活更轻松(而且代码更清晰)的东西。

所以,给一个InputStream和一个OutputStream ,有没有更简单的方法来编写以下内容?

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

正如WMR提到的,来自Apache的org.apache.commons.io.IOUtils有一个叫做copy(InputStream,OutputStream) ,它正是你所要找的。

所以,你有:

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

…在你的代码。

你有避免IOUtils的原因吗?

如果您使用Java 7,则文件 (在标准库中)是最好的方法:

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

编辑:当然,从文件中创buildInputStream或OutputStream时,它是很有用的。 使用file.toPath()从文件中获取path。

要写入现有文件(例如使用File.createTempFile()创build的文件),您需要传递REPLACE_EXISTING复制选项(否则引发FileAlreadyExistsException ):

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

我认为这将起作用,但是要确保testing它…小的“改进”,但是在可读性方面可能会有一点成本。

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

Java 9

从Java 9开始, InputStream提供了一个名为transferTo的方法,其签名如下:

 public long transferTo(OutputStream out) throws IOException 

正如文档所述, transferTo将:

从该inputstream中读取所有字节,并按照读取的顺序将字节写入给定的输出stream。 返回时,这个inputstream将在stream的末尾。 此方法不closures任何stream。

这种方法可能会无限期地从inputstream中读取数据,或者写入输出数据stream。 input和/或输出streamasynchronousclosures或者在传输过程中线程中断的情况下的行为是高度input和输出stream特定的,因此没有指定

所以为了将Java InputStream内容写入到OutputStream ,可以这样写:

 input.transferTo(output); 

使用番石榴的ByteStreams.copy()

 ByteStreams.copy(inputStream, outputStream); 

简单的function

如果你只需要将这个InputStream写入一个File那么你可以使用这个简单的函数:

 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(); } } 

PipedInputStreamPipedOutputStream应该只在有多个线程时使用,如Javadoc所述 。

另外,请注意inputstream和输出stream不会用IOException封装任何线程中断…因此,您应该考虑将中断策略合并到您的代码中:

 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(); } } 

如果您希望使用此API来复制大量的数据,或者来自数据stream的数据难以忍受,那么这将是一个有用的补充。

使用JDK方法没有办法做到这一点,但是正如Apocalisp已经指出的那样,您不是唯一有这个想法的人:您可以使用来自Jakarta Commons IO的 IOUtils ,它还有很多其他有用的东西,国际海事组织实际上应该是JDK的一部分

使用Java7并尝试与资源 ,来与一个简化和可读的版本。

  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(); } 

JDK使用相同的代码,所以似乎没有笨重的第三方库(这可能不会做任何不同的事情)没有“更容易”的方式。 以下是从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; } 

使用Commons Net的Util类:

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

我认为最好使用一个大的缓冲区,因为大部分文件大于1024字节。 此外,检查读取字节数是肯定的是一个好习惯。

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

这里是我如何做最简单的循环。

 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); } } 

对于那些使用Spring框架的人来说,有一个有用的StreamUtils类:

 StreamUtils.copy(in, out); 

以上不closuresstream。 如果您想在复制之后closuresstream,请改用FileCopyUtils类:

 FileCopyUtils.copy(in, out); 

PipedInputStream和PipedOutputStream可能有一些用处,因为你可以将一个连接到另一个。

另一个可能的候选者是番石榴I / O公用事业:

http://code.google.com/p/guava-libraries/wiki/IOExplained

我以为我会使用这些,因为番石榴在我的项目中已经非常有用,而不是增加另一个函数库。

一个恕我直言更多最小的片段(也更狭窄范围的长度variables):

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

作为一个侧面说明,我不明白为什么更多的人不使用for循环,而是select一个被认为是“穷人”风格的分配和testingexpression式。

尝试Cactoos :

 new LengthOf(new TeeInput(input, output)).value(); 

更多细节在这里: http : //www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html

 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; } 

你可以使用这个方法

 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){} }