Java NIO 學(xué)習(xí)筆記(二)----聚集和分散,通道到通道

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

Scatter / Gather 通道的聚集和分散操作

NIO 具有內(nèi)置的 scatter/gather 支持,用于描述讀取和寫入通道的操作。

  • 分散(scatter)地從 Channel 中讀取是將數(shù)據(jù)讀入多個 Buffer 的操作。 因此,通道將來自通道的數(shù)據(jù)“分散”到多個緩沖區(qū)中。
  • 聚集(gather)地寫入 Channel 是將來自多個緩沖區(qū)的數(shù)據(jù)寫入單個通道的操作。 因此,通道將來自多個緩沖區(qū)的數(shù)據(jù)“收集”到同一個通道中。

通道的聚集和分散操作在需要將傳輸?shù)臄?shù)據(jù)分開處理的場合非常有用,例如,如果消息由標題和正文組成,則可以將標題和正文保留在單獨的緩沖區(qū)中,這樣做可以更容易處理標題和正文。

Scattering Reads 分散讀取

是指將數(shù)據(jù)從單個通道讀入多個緩沖區(qū):

image

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

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

        ByteBuffer buffer1 = ByteBuffer.allocate(5); // 分配第一個緩沖區(qū),大小為 5
        ByteBuffer buffer2 = ByteBuffer.allocate(128);
        ByteBuffer[] buffers = {buffer1, buffer2}; // 兩個緩沖區(qū)的數(shù)組

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

        long data = channel.read(buffers); // 一次性把通道的數(shù)據(jù)讀入2個緩沖區(qū)
        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

注意多個緩沖區(qū)首先插入到數(shù)組中,然后將數(shù)組作為參數(shù)傳遞給 channel.read() 方法。 然后,read()方法按照緩沖區(qū)在數(shù)組中出現(xiàn)的順序從通道寫入數(shù)據(jù)。 一旦緩沖區(qū)已滿,通道就會繼續(xù)填充下一個緩沖區(qū)。
分散讀取在移動到下一個緩沖區(qū)之前,必須先填充慢前一個緩沖區(qū),這意味著它不適合大小不固定的消息。

Gathering Writes 聚集寫入

“聚集寫入”將來自多個緩沖區(qū)的數(shù)據(jù)寫入單個通道:

image

一個示例:

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

channel.write(bufferArray);

將緩沖區(qū)數(shù)組傳遞給 write() 方法,該方法按照在數(shù)組的順序?qū)懭刖彌_區(qū)的內(nèi)容到單個通道,注意僅寫入緩沖區(qū)的 position 和 limit 之間的數(shù)據(jù)。 因此,如果緩沖區(qū)的容量為 128 字節(jié),但只包含 58 字節(jié)的內(nèi)容,則只有 58 字節(jié)從該緩沖區(qū)寫入通道。 因此,與 Scattering Reads 相比,Gathering Writes 可以適應(yīng)大小不固定的數(shù)據(jù),因為它只把包含內(nèi)容部分的緩沖區(qū)寫入到通道。

Channel to Channel 通道到通道傳輸

在 NIO 中,如果其中一個通道是 FileChannel ,可以直接將數(shù)據(jù)從一個通道傳輸?shù)搅硪粋€通道。 FileChannel 類有一個 transferTo() 和 transferFrom() 方法。

transferFrom() 和 transferTo()

FileChannel 對象的 transferFrom() 方法將數(shù)據(jù)從源通道傳輸?shù)?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);
    }
}

參數(shù) position 和 count,告訴目標文件中開始寫入的位置以及最大傳輸?shù)淖止?jié)數(shù)(總數(shù))。 如果源通道的字節(jié)數(shù)少于 count ,則傳輸實際字節(jié)數(shù)。

此外,一些 SocketChannel 實現(xiàn)可能現(xiàn)在只傳輸 SocketChannel 在其內(nèi)部緩沖區(qū)中準備好的數(shù)據(jù) - 即使 SocketChannel 可能稍后有更多可用數(shù)據(jù)。 因此,它可能不會將請求的整個數(shù)據(jù)(count)從 SocketChannel 傳輸?shù)?FileChannel 。

transferTo() 方法的效果除了目標和參數(shù)位置不一致,其他部分同 transferFrom() 方法一樣,上面代碼如果換成執(zhí)行 fromChannel.transferTo(position, count, toChannel); input.txt 的內(nèi)容同樣會被立即復(fù)制到 receive.txt。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容