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模型實現聊天室
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章