我试图找到将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
============================================
'动态缓冲区读取'使用available()
方法。但根据java docs
使用此方法的返回值进行分配永远不正确 用于保存此流中所有数据的缓冲区。
'Byte Read'似乎非常慢。
所以'固定缓冲读取'是管道的最佳选择吗?有什么想法吗?
答案 0 :(得分:12)
我想说固定的缓冲区大小是最好/最容易理解的。但是有一些问题。
您每次都将整个缓冲区写入输出流。对于最后的块,读取可能已读取< 1024字节,因此在执行写操作时需要考虑这一点(基本上只有read()
在动态缓冲区中,您使用available()
。这不是一个非常可靠的API调用。在这种情况下,我不确定它是否正常,但如果在InputStream的某些实现中以次优的方式实现,我不会感到惊讶。
您要投放到FileInputStream
的最后一个案例。如果您打算将此作为一般用途,则不能使用此方法。
答案 1 :(得分:12)
我遇到了这个,最后的阅读可能会导致问题。
建议更改:
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更好的固定缓冲区大小。
... IMHO
答案 2 :(得分:8)
对于寻找单行的人来说,这是apache commons的解决方案:
IOUtils.copy(inputStream, outputStream);
Documentation here。有多个copy
方法具有不同的参数。也可以指定缓冲区大小。
答案 3 :(得分:6)
java.io
包含PipedInputStream
和PipedOutputStream
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream (input);
写入输入,它将在输出中显示为Outputstream
。事情也可以反过来