JavaIO之NIO,BIO的复制文件的简单比较(3)

本文展示BIO,NIO复制文件的不同写法,和一丢丢的效率对比。

在演示NIO之前 ,先简单说一下 NIO
在BIO中,根据方向的不同,分为输入流,输出流,而在NIO中,就没有这个概念了,NIO中,提出了Channel的概念,一个通道是可以读也可以写的。channel通过和Buffer的交互,可以往buffer写数据也可以读数据,这是怎么实现的呢?
首先,Buffer是一个数组,有三个重要的指针。
buffer的大小/容量 - Capacity
当前读/写的位置 - Position​
信息末尾的位置 - limit
初始化的时候,他们的分布是这个样子的(找文件夹的图片真的太难翻了,我直接截图我的MD)。
在这里插入图片描述
假设写了3份数据。
在这里插入图片描述
这个时候想读取数据了,这个时候调用flip()函数,会发生这样的过程。
position回到起点,limit指针在原来position的位置。

在这里插入图片描述
假设数据读取完毕,调用clear()函数,buffer又会变成原来的样子,变成写入模式。
在这里插入图片描述
在这里插入图片描述
如果在读数据的时候,并没有读取完数据,还想下次继续读取且不影响写入呢
在这里插入图片描述
此时调用compact()函数,buffer会拷贝没有读取完的数据从起点开始存放,并且调整指针。
在这里插入图片描述
这样大概明白了吧,但是Channel之间也是可以之间通信的。
下面展示复制文件的用法
为了使用上的方便,首先定义一个文件复制的接口。

public interface FileCopyRunner {
    void copyFile(File source,File target);
}

main函数中分别实现不同的方式:

 		FileCopyRunner noBufferStreamCopy;
        FileCopyRunner bufferStreamCopy;
        FileCopyRunner nioBufferCopy;
        //two channel
        FileCopyRunner nioTransferCopy;
        

noBufferStreamCopy:

noBufferStreamCopy = new FileCopyRunner() {
            @Override
            public void copyFile(File source, File target) {
                InputStream fin = null;
                OutputStream fout = null;
                try {
                    fin = new FileInputStream(source);
                    fout = new FileOutputStream(target);
                    int result;
                    while ((result = fin.read()) != -1) {
                        fout.write(result);
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                   close(fin);
                   close(fout);
                }
            }

            @Override
            public String toString() {
                return "noBufferStreamCopy";
            }
        };

bufferStreamCopy:

 bufferStreamCopy = new FileCopyRunner() {
            @Override
            public void copyFile(File source, File target) {
                InputStream fin = null;
                OutputStream fout = null;
                try {
                    fin = new BufferedInputStream(new FileInputStream(source));
                    fout = new BufferedOutputStream(new FileOutputStream(target));
                    byte[] buffer = new byte[1024];
                    int result;
                    while ((result = fin.read(buffer)) != -1){
                        fout.write(buffer,0,result);
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    close(fin);
                    close(fout);
                }
            }
            @Override
            public String toString() {
                return "bufferStreamCopy";
            }
        };

nioBufferCopy:

 nioBufferCopy = new FileCopyRunner() {
            @Override
            public String toString() {
                return "nioBufferCopy";
            }
            @Override
            public void copyFile(File source, File target) {
                FileChannel fin = null;
                FileChannel fout = null;
                try {
                    fin = new FileInputStream(source).getChannel();
                    fout = new FileOutputStream(target).getChannel();
                    ByteBuffer buffer =ByteBuffer.allocate(1024);
                   while ((fin.read(buffer)) != -1){
                       //转换模式
                       buffer.flip();
                       while (buffer.hasRemaining()){
                           fout.write(buffer);
                       }
                       //写完后,再把指针还原
                       buffer .clear();
                   }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    close(fin);
                    close(fout);
                }
            }
        };

nioTransferCopy:

nioTransferCopy = new FileCopyRunner() {
            @Override
            public String toString() {
                return "nioBufferCopy";
            }
            @Override
            public void copyFile(File source, File target) {
                FileChannel fin = null;
                FileChannel fout = null;
                try {
                    fin = new FileInputStream(source).getChannel();
                    fout = new FileOutputStream(target).getChannel();
                     long transfer =0L;
                     long size = fin.size();
                    //开始拷贝数据的位置,
                    while (transfer != fin.size()) {
                         transfer += fin.transferTo(0, size, fout);
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    close(fin);
                    close(fout);
                }

            }
        };

平均复制粘贴5次比较效率 :

 private static final int ROUNDS = 5;

    private static void benchmark(FileCopyRunner test,File source,File target){
        long elapsed = 0L;
        for (int i = 0; i <ROUNDS ; i++) {
            long startTime = System.currentTimeMillis();
            test.copyFile(source,target);
            long endTime = System.currentTimeMillis();
            elapsed+=endTime-startTime;
            //最后要删的哈
            target.delete();
        }
        System.out.println(test + ":" + elapsed/ROUNDS );
    }
 File sourceFile = new File("C:/Users/12479/Desktop/SB核心篇章/源码、资料、课件.rar");
        File targetFile = new File("C:/Users/12479/Desktop/SB核心篇章/n源码、资料、课件.rar");
//        benchmark(noBufferStreamCopy,sourceFile,targetFile);
        benchmark(bufferStreamCopy,sourceFile,targetFile);
        benchmark(nioBufferCopy,sourceFile,targetFile);
        benchmark(nioTransferCopy,sourceFile,targetFile);

知道我为啥把第一个注释了吗?最开始我是没有注释的,但是惊人的事情发生了,我开始测试的文件是1.5Gb,5个来回7个多G吧?我的天呐,我12点吃饭我吃完饭等到1点啊!!
我就直接贴结果了:
/**

  • 80M
  • noBufferStreamCopy:326448
  • bufferStreamCopy:159
  • nioBufferCopy:486
  • nioBufferCopy:81
  • 1.5GB
  • bufferStreamCopy:27624
  • nioBufferCopy:35141
  • nioBufferCopy:21027
    */
    下篇预告:基于NIO模型实现聊天室
发布了11 篇原创文章 · 获赞 1 · 访问量 604

猜你喜欢

转载自blog.csdn.net/Fujie1997/article/details/104762369