对于文件拷贝,传统的io是先从输入流中取出一小部分字节,然后写入输出流中。而nio是将输入流对应的channel直接transfer到输出流对应的channel,避免了中间的byte数组的缓冲区,这也是所谓零拷贝的一种。
public class FileIOTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//ioTest();
//nioTest();
bufferStreamTest1();
}
private static void bufferStreamTest1() {
// TODO Auto-generated method stub
long startTime=System.currentTimeMillis();
try {
FileInputStream inputStream=new FileInputStream(new File("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字.rmvb"));
FileOutputStream outputStream=new FileOutputStream(new File("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字buffer.mkv"));
BufferedInputStream bufferInputStream=new BufferedInputStream(inputStream,1024);
BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(outputStream,1024);
byte[] b=new byte[1024];
while (bufferInputStream.read(b)>0) {
bufferedOutputStream.write(b);
}
bufferInputStream.close();
bufferInputStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long endTime=System.currentTimeMillis();
System.out.println("BufferedInputStreamfile文件时间--》"+(endTime-startTime));
}
/**
* niochannel测试
* @throws IOException
*/
private static void nioTest() throws IOException {
// TODO Auto-generated method stub
long startTime=System.currentTimeMillis();
RandomAccessFile inFile=new RandomAccessFile("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字.rmvb","rw");
RandomAccessFile outFile=new RandomAccessFile("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字nio.rmvb","rw");
FileChannel inchannel = inFile.getChannel();
FileChannel outchannel = outFile.getChannel();
long size = inchannel.size();
inchannel.transferTo(0, size, outchannel);
long endTime=System.currentTimeMillis();
System.out.println("nio文件时间--》"+(endTime-startTime));
inchannel.close();
outchannel.close();
}
/**
* 普通io文件测试
* @throws IOException
*/
private static void ioTest() throws IOException {
// TODO Auto-generated method stub
long startTime=System.currentTimeMillis();
File infile=new File("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字.rmvb");
FileInputStream inputStream=new FileInputStream(infile);
File outfile=new File("F:/娱乐/[电影天堂www.dy2018.com]杰出公民BD西班牙中字io.rmvb");
FileOutputStream outputStream=new FileOutputStream(outfile);
byte[] temp=new byte[1024];
int len=0;
while ((len=inputStream.read(temp))>0 ) {
outputStream.write(temp);
}
long endTime=System.currentTimeMillis();
System.out.println("普通io文件时间--》"+(endTime-startTime));
inputStream.close();
outputStream.close();
}
}
上面代码对一个电影进行了拷贝,结果是:
普通io文件时间–》7669
nio文件时间–》727
BufferedInputStreamfile文件时间–》7289.
说明nio处理文件效率要高很多。
附:
netty的零拷贝的另外几种情况是:
1、例如我们有一个 byte 数组, 我们希望将它转换为一个 ByteBuf 对象, 以便于后续的操作, 那么传统的做法是将此 byte 数组拷贝到 ByteBuf 中, 即:
byte[] bytes = …
ByteBuf byteBuf = Unpooled.buffer();
byteBuf.writeBytes(bytes);
显然这样的方式也是有一个额外的拷贝操作的, 我们可以使用 Unpooled 的相关方法, 包装这个 byte 数组, 生成一个新的 ByteBuf 实例, 而不需要进行拷贝操作. 上面的代码可以改为:
byte[] bytes = …
ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
可以看到, 我们通过 Unpooled.wrappedBuffer 方法来将 bytes 包装成为一个 UnpooledHeapByteBuf 对象, 而在包装的过程中, 是不会有拷贝操作的. 即最后我们生成的生成的 ByteBuf 对象是和 bytes 数组共用了同一个存储空间, 对 bytes 的修改也会反映到 ByteBuf 对象中.
2、通过使用compositeByteBuf.addComponents(bytebuf),将两个bytebuf进行组合,形成逻辑上的bytebuf,不用新建bytebyf,然后write,避免了bytebuf的分配及写操作
3、bytebuf的浅拷贝,slice