Java NIO 學習筆記(二)----彙集和分散,通道到通道

目錄:
Java NIO 學習筆記(一)----概述,Channel/Buffer
Java NIO 學習筆記(二)----彙集和分散,通道到通道
Java NIO 學習筆記(三)----Selector
Java NIO 學習筆記(四)----文件通道和網絡通道
Java NIO 學習筆記(五)----路徑、文件和管道 Path/Files/Pipe
Java NIO 學習筆記(六)----異步文件通道 AsynchronousFileChannel
Java NIO 學習筆記(七)----NIO/IO 的對比和總結html

Scatter / Gather 通道的彙集和分散操做

NIO 具備內置的 scatter/gather 支持,用於描述讀取和寫入通道的操做。java

  • 分散(scatter)地從 Channel 中讀取是將數據讀入多個 Buffer 的操做。 所以,通道未來自通道的數據「分散」到多個緩衝區中。
  • 彙集(gather)地寫入 Channel 是未來自多個緩衝區的數據寫入單個通道的操做。 所以,通道未來自多個緩衝區的數據「收集」到同一個通道中。

通道的彙集和分散操做在須要將傳輸的數據分開處理的場合很是有用,例如,若是消息由標題和正文組成,則能夠將標題和正文保留在單獨的緩衝區中,這樣作能夠更容易處理標題和正文。數組

Scattering Reads 分散讀取

是指將數據從單個通道讀入多個緩衝區:網絡

image

下面是一個代碼示例,演示如何執行分散讀取:dom

public class ScatteringReads {
    public static void main(String[] args) throws IOException {

        ByteBuffer buffer1 = ByteBuffer.allocate(5); // 分配第一個緩衝區,大小爲 5
        ByteBuffer buffer2 = ByteBuffer.allocate(128);
        ByteBuffer[] buffers = {buffer1, buffer2}; // 兩個緩衝區的數組

        File file = new File("D:\\test\\1.txt"); // 文件內容是 012345678
        RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
        FileChannel channel = accessFile.getChannel();

        long data = channel.read(buffers); // 一次性把通道的數據讀入2個緩衝區
        System.out.println("Read: " + data); // Read 9

        System.out.println("開始讀取第一個 buffer :");
        buffer1.flip(); // 將 buffer 從寫入模式切換爲讀取模式
        while (buffer1.hasRemaining()) {
            System.out.print((char) buffer1.get()); // 每次讀取1byte,輸出 01234
        }

        System.out.println("\n開始讀取第二個 buffer :");

        buffer2.flip();
        while (buffer2.hasRemaining()) {
            System.out.print((char) buffer2.get()); // 輸出 5678
        }
    }
}

將會輸出:異步

Read: 9
開始讀取第一個 buffer :
01234
開始讀取第二個 buffer :
5678

注意多個緩衝區首先插入到數組中,而後將數組做爲參數傳遞給 channel.read() 方法。 而後,read()方法按照緩衝區在數組中出現的順序從通道寫入數據。 一旦緩衝區已滿,通道就會繼續填充下一個緩衝區。
分散讀取在移動到下一個緩衝區以前,必須先填充慢前一個緩衝區,這意味着它不適合大小不固定的消息。學習

Gathering Writes 彙集寫入

「彙集寫入」未來自多個緩衝區的數據寫入單個通道:code

image

一個示例:htm

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
//write data into buffers...

channel.write(bufferArray);

將緩衝區數組傳遞給 write() 方法,該方法按照在數組的順序寫入緩衝區的內容到單個通道,注意僅寫入緩衝區的 position 和 limit 之間的數據。 所以,若是緩衝區的容量爲 128 字節,但只包含 58 字節的內容,則只有 58 字節從該緩衝區寫入通道。 所以,與 Scattering Reads 相比,Gathering Writes 能夠適應大小不固定的數據,由於它只把包含內容部分的緩衝區寫入到通道。對象

Channel to Channel 通道到通道傳輸

在 NIO 中,若是其中一個通道是 FileChannel ,能夠直接將數據從一個通道傳輸到另外一個通道。 FileChannel 類有一個 transferTo() 和 transferFrom() 方法。

transferFrom() 和 transferTo()

FileChannel 對象的 transferFrom() 方法將數據從源通道傳輸到 FileChannel。 這是一個簡單的例子:

public class TransfetExample {
    public static void main(String[] args) throws IOException {
        RandomAccessFile fromFile = new RandomAccessFile("D:\\test\\input.txt", "rw");
        FileChannel fromChannel = fromFile.getChannel();

        RandomAccessFile toFile = new RandomAccessFile("D:\\test\\receive.txt", "rw");
        FileChannel toChannel = toFile.getChannel();

        long position = 0;
        long count = fromChannel.size();

        toChannel.transferFrom(fromChannel, position, count);
    }
}

參數 position 和 count,告訴目標文件中開始寫入的位置以及最大傳輸的字節數(總數)。 若是源通道的字節數少於 count ,則傳輸實際字節數。

此外,一些 SocketChannel 實現可能如今只傳輸 SocketChannel 在其內部緩衝區中準備好的數據 - 即便 SocketChannel 可能稍後有更多可用數據。 所以,它可能不會將請求的整個數據(count)從 SocketChannel 傳輸到 FileChannel 。

transferTo() 方法的效果除了目標和參數位置不一致,其餘部分同 transferFrom() 方法同樣,上面代碼若是換成執行 fromChannel.transferTo(position, count, toChannel); input.txt 的內容一樣會被當即複製到 receive.txt。

相關文章
相關標籤/搜索