将InputStream传递给OutputStream的最佳方法

我试图找到将InputStream传递给OutputStream的最佳方法。 我没有选择使用Apache IO之类的任何其他库。 这是片段和输出。

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.channels.FileChannel; public class Pipe { public static void main(String[] args) throws Exception { for(PipeTestCase testCase : testCases) { System.out.println(testCase.getApproach()); InputStream is = new FileInputStream("D:\\in\\lft_.txt"); OutputStream os = new FileOutputStream("D:\\in\\out.txt"); long start = System.currentTimeMillis(); testCase.pipe(is, os); long end = System.currentTimeMillis(); System.out.println("Execution Time = " + (end - start) + " millis"); System.out.println("============================================"); is.close(); os.close(); } } private static PipeTestCase[] testCases = { new PipeTestCase("Fixed Buffer Read") { @Override public void pipe(InputStream is, OutputStream os) throws IOException { byte[] buffer = new byte[1024]; while(is.read(buffer) > -1) { os.write(buffer); } } }, new PipeTestCase("dynamic Buffer Read") { @Override public void pipe(InputStream is, OutputStream os) throws IOException { byte[] buffer = new byte[is.available()]; while(is.read(buffer) > -1) { os.write(buffer); buffer = new byte[is.available() + 1]; } } }, new PipeTestCase("Byte Read") { @Override public void pipe(InputStream is, OutputStream os) throws IOException { int c; while((c = is.read()) > -1) { os.write(c); } } }, new PipeTestCase("NIO Read") { @Override public void pipe(InputStream is, OutputStream os) throws IOException { FileChannel source = ((FileInputStream) is).getChannel(); FileChannel destnation = ((FileOutputStream) os).getChannel(); destnation.transferFrom(source, 0, source.size()); } }, }; } abstract class PipeTestCase { private String approach; public PipeTestCase( final String approach) { this.approach = approach; } public String getApproach() { return approach; } public abstract void pipe(InputStream is, OutputStream os) throws IOException; } 

输出(~4MB输入文件):

 Fixed Buffer Read Execution Time = 71 millis ============================================ dynamic Buffer Read Execution Time = 167 millis ============================================ Byte Read Execution Time = 29124 millis ============================================ NIO Read Execution Time = 125 millis ============================================ 

‘Dynamic Buffer Read’使用available()方法。 但根据java docs,它并不可靠

使用此方法的返回值来分配用于保存此流中所有数据的缓冲区绝对不正确。

‘Byte Read’似乎很慢。

那么’固定缓冲读取’是管道的最佳选择吗? 有什么想法吗?

我想说固定的缓冲区大小是最好/最容易理解的。 但是有一些问题。

  • 您每次都将整个缓冲区写入输出流。 对于最后的块,读取可能已读取<1024字节,因此在执行写入时需要考虑这一点(基本上只read()返回的写入字节数

  • 在动态缓冲区的情况下,您使用available() 。 这不是一个非常可靠的API调用。 在这种情况下,我不确定它是否正常,但如果它在InputStream的某些实现中以次优的方式实现,我不会感到惊讶。

  • 您要转换为FileInputStream的最后一种情况。 如果您打算将此作为通用目的,则不能使用此方法。

我遇到了这个,最后的阅读可能会导致问题。

建议更改:

 public void pipe(InputStream is, OutputStream os) throws IOException { int n; byte[] buffer = new byte[1024]; while((n = is.read(buffer)) > -1) { os.write(buffer, 0, n); // Don't allow any extra bytes to creep in, final write } os.close (); 

我也同意16384可能是比1024更好的固定缓冲区大小。

恕我直言…

对于寻找单行的人来说 ,这是apache commons的解决方案:

 IOUtils.copy(inputStream, outputStream); 

文档在这里 。 有多种copy方法具有不同的参数。 也可以指定缓冲区大小。

java.io包含PipedInputStreamPipedOutputStream

 PipedInputStream input = new PipedInputStream(); PipedOutputStream output = new PipedOutputStream (input); 

写入输入,它将在输出中作为Outputstream可见。 事情也可以相反