Best way to Pipe InputStream to OutputStream
本问题已经有最佳答案,请猛点这里访问。
我试图找到最好的方法把输入流输送到输出流。我没有选择使用任何其他库,如ApacheIO。这是片段和输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 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输入文件):
1 2 3 4 5 6 7 8 9 10 11 12 | 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 ============================================ |
号
"动态缓冲区读取"使用
It is never correct to use the return value of this method to allocate
a buffer intended to hold all data in this stream.
号
"字节读取"似乎非常慢。
所以"固定缓冲区读取"是管道的最佳选择?有什么想法吗?
我发现了这一点,最终的阅读可能会引起问题。
建议变更:
1 2 3 4 5 6 7 | 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更好的固定缓冲区大小。
我不知道…
我想说,固定的缓冲区大小是最好/最容易理解的。但也有一些问题。
每次都将整个缓冲区写入输出流。对于最后一个块,读取的字节数可能小于1024字节,因此在进行写入时需要考虑到这一点(基本上只写由EDOCX1返回的字节数〔0〕。
在动态缓冲区的情况下,使用
available() 。这不是一个非常可靠的API调用。在本例中,我不确定在一个循环中它是否可以,但是如果它在一些inputstream实现中被次优化地实现,我不会感到惊讶。最后一个案例是你向
FileInputStream 发起的。如果您打算将此作为通用目的,那么就不能使用此方法。
对于寻找一行程序的人,以下是ApacheCommons的一个解决方案:
1 | IOUtils.copy(inputStream, outputStream); |
号
此处为文档。有多种不同参数的
1 2 | PipedInputStream input = new PipedInputStream(); PipedOutputStream output = new PipedOutputStream (input); |
写入输入,它将在输出中以