1. 程式人生 > >NIO Channel

NIO Channel

在傳統IO中, 若有大量IO操作, 會佔用cpu資源, 效能下降
使用DMA時, 由DMA處理IO請求。但若有大量IO操作時, 會發生DMA匯流排衝突, 也會影響效能
使用Channel時,其專用於IO操作, cpu利用率更高, 效能更高

Channel的主要實現類


java.nio.channels.channel介面
|--FileChannel 本地檔案
|--SocketChannel 用於網路
|--ServerSocketChannel 用於網路
|--DatagramChannel 用於網路

java中獲取通道的方式


  • 對支援通道的類提供了getChannel方法

本地IO:

  • FileInputStream/FileOutputStream
  • RandomAccessFile
    網路IO:
  • Socket
  • ServerSocket
  • DatagramSocket
//    利用通道完成檔案的複製(非直接緩衝區)
        final FileInputStream fis = new FileInputStream("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png");
        final FileOutputStream fos = new FileOutputStream("F:\\ProgarmData\\SystemFoler\\Pictures\\2.png");
//        1.獲取通道
        final FileChannel inChannel = fis.getChannel();
        final FileChannel outChannel = fos.getChannel();
//            2分配指定大小的緩衝區
        final ByteBuffer buf = ByteBuffer.allocate(1024);
//        3.將通道中的資料存入緩衝區中
        while(inChannel.read(buf) != -1){
            buf.flip();//切換讀資料模式
            //            4.將緩衝區的資料寫入通道中
            outChannel.write(buf);
            buf.clear();//情況緩衝區


        }
        outChannel.close();
        inChannel.close();
        fos.close();
        fis.close();


  • (1.7之後)各個通道類提供了靜態方法open()

//    使用直接緩衝區完成檔案的複製(記憶體檔案對映)
        final FileChannel inChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"), StandardOpenOption.READ);
        final FileChannel outChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\3.png"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
//記憶體對映檔案
        final MappedByteBuffer inMappedBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        final MappedByteBuffer outMappedBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
// 直接對緩衝區進行資料的讀寫操作
        byte[] dst = new byte[inMappedBuffer.limit()];
        inMappedBuffer.get(dst);
        outMappedBuffer.put(dst);
        inChannel.close();
        outChannel.close();


  • (1.7之後)Files工具類的newBytesChannel()

通道之間的資料傳輸


transferFrom() 從其他通道傳入
transferTo() 傳向其他通道

        final FileChannel inChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\1.png"), StandardOpenOption.READ);
        final FileChannel outChannel = FileChannel.open(Paths.get("F:\\ProgarmData\\SystemFoler\\Pictures\\5.png"), StandardOpenOption.WRITE, StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);

//        inChannel.transferTo(0, inChannel.size(), outChannel);
        outChannel.transferFrom(inChannel, 0, inChannel.size());
        inChannel.close();
        outChannel.close();


分散與聚集


分散讀取 Scattering Reads : 將通道中的資料分散到多個緩衝區中
聚集寫入 Gathering Writes : 將多個緩衝區中的資料聚集到通道中

//        獲取通道
        final RandomAccessFile raf1 = new RandomAccessFile("D:\\weblog.txt", "rw");
        final FileChannel channel = raf1.getChannel();
//        分配指定大小的緩衝區
        final ByteBuffer buf1 = ByteBuffer.allocate(100);
        final ByteBuffer buf2 = ByteBuffer.allocate(1024);

//        分散讀取
        ByteBuffer[] bufs = {buf1, buf2};
        channel.read(bufs);
        for(ByteBuffer byteBuffer: bufs){
            byteBuffer.flip();
        }
        System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));
        System.out.println("--------------");
        System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));

//        聚集寫入
        final RandomAccessFile raf2 = new RandomAccessFile("D:\\ tt.txt", "rw");
        final FileChannel channel2 = raf2.getChannel();
        channel2.write(bufs);


字符集


編碼: 字串 -> 位元組陣列
解碼: 位元組資料 -> 字串

        final Charset cs1 = Charset.forName("GBK");
//        獲取編碼器
        final CharsetEncoder ce = cs1.newEncoder();
//        獲取解碼器
        final CharsetDecoder cd = cs1.newDecoder();

        final CharBuffer buf = CharBuffer.allocate(1024);
        buf.put("呵呵噠");
        buf.flip();
//        編碼
        final ByteBuffer bBuf = ce.encode(buf);
//        解碼
        final CharBuffer buf2 = cd.decode(bBuf);
        System.out.println(buf2.toString());

        final Charset cs2 = Charset.forName("utf-8");
        bBuf.rewind();
        final CharBuffer buf3 = cs2.decode(bBuf);
        System.out.println(buf3.toStri