日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NIO入门系列之第4章:缓冲区内部细节

發布時間:2024/4/14 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NIO入门系列之第4章:缓冲区内部细节 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

4.1 ?概述

本節將介紹 NIO 中兩個重要的緩沖區組件:狀態變量和訪問方法 (accessor)

狀態變量是前一節中提到的"內部統計機制"的關鍵。每一個讀/寫操作都會改變緩沖區的狀態。通過記錄和跟蹤這些變化,緩沖區就可能夠內部地管理自己的資源

在從通道讀取數據時,數據被放入到緩沖區。在有些情況下,可以將這個緩沖區直接寫入另一個通道,但是在一般情況下,您還需要查看數據。這時使用訪問方法 get() 來完成的。同樣,如果要將原始數據放入緩沖區中,就要使用訪問方法 put()

在本節中,您將學習關于NIO 中的狀態變量和訪問方法的內容。我們將描述每一個組件,并讓您有機會看到它的實際應用。雖然 NIO 的內部統計機制初看起來可能很復雜,但是您很快就會看到大部分的實際工作都已經替您完成了。您可能習慣于通過手工編碼進行簿記即使用字節數組和索引變量,現在它已在 NIO 中內部地處理了。


4.2 ?狀態變量

可以用三個值指定緩沖區在任意時刻的狀態:

position

limit

capacity

參數

寫模式

讀模式

位置(position

當前緩沖區的位置,將從position的下一個位置寫數據

當前緩沖區讀取的位置,將從此位置后,讀取數據

容量(capacity

緩沖區的總量上限

緩沖區的總量上限

上限(capacity

緩沖區的實際上限,它總是小于或等于容量。通常情況下,和容量相等

代表可讀取的總容量,和上次寫入的數據量相等


這三個變量一起可以跟蹤緩沖區的狀態和它所包含的數據。我們將在下面的小節中詳細分析每一個變量,還要介紹它們如何適應典型的讀/(輸入/輸出)進程。在這個例子中,我們假定要將數據從一個輸入通道拷貝到一個輸出通道。


4.3 ?Position

您可以回想一下,緩沖區實際上就是美化了的數組。在從通道讀取時,您將所讀取的數據放到底層的數組中。 position 變量跟蹤已經寫了多少數據。更準確地說,它指定了下一個字節將放到數組的哪一個元素中。因此,如果您從通道中讀三個字節到緩沖區中,那么緩沖區的 position 將會設置為3,指向數組中第四個元素。

同樣,在寫入通道時,您是從緩沖區中獲取數據。 position 值跟蹤從緩沖區中獲取了多少數據。更準確地說,它指定下一個字節來自數組的哪一個元素。因此如果從緩沖區寫了5個字節到通道中,那么緩沖區的position 將被設置為5,指向數組的第六個元素。


4.4 ?Limit

limit 變量表明還有多少數據需要取出(在從緩沖區寫入通道時),或者還有多少空間可以放入數據(在從通道讀入緩沖區時)

position 總是小于或者等于 limit


4.5 ?Capacity

緩沖區的 capacity 表明可以儲存在緩沖區中的最大數據容量。實際上,它指定了底層數組的大小或者至少是指定了準許我們使用的底層數組的容量。

limit 決不能大于 capacity


4.6 ?觀察變量

我們首先觀察一個新創建的緩沖區。出于本例子的需要,我們假設這個緩沖區的總容量8個字節。 Buffer 的狀態如下所示:

回想一下limit 決不能大于 capacity,此例中這兩個值都被設置為 8。我們通過將它們指向數組的尾部之后(如果有第8個槽,則是第8個槽所在的位置)來說明這點。

position 設置為0。如果我們讀一些數據到緩沖區中,那么下一個讀取的數據就進入 slot 0 。如果我們從緩沖區寫一些數據,從緩沖區讀取的下一個字節就來自 slot 0 position 設置如下所示:

由于 capacity 不會改變,所以我們在下面的討論中可以忽略它。


4.7 ?第一次讀取

現在我們可以開始在新創建的緩沖區上進行讀/寫操作。首先從輸入通道中讀一些數據到緩沖區中。第一次讀取得到三個字節。它們被放到數組中從 position 開始的位置,這時 position 被設置為 0。讀完之后,position就增加到 3,如下所示:

limit 沒有改變。

4.8 ?第二次讀取

在第二次讀取時,我們從輸入通道讀取另外兩個字節到緩沖區中。這兩個字節儲存在由 position 所指定的位置上, position 因而增加 2

limit 沒有改變。


4.9 ?flip

現在我們要將數據寫到輸出通道中。在這之前,我們必須調用 flip() 方法。這個方法做兩件非常重要的事:

1.它將 limit 設置為當前 position

2.它將 position 設置為 0

前一小節中的圖顯示了在flip 之前緩沖區的情況。下面是在flip 之后的緩沖區:


我們現在可以將數據從緩沖區寫入通道了。 position 被設置為 0,這意味著我們得到的下一個字節是第一個字節。 limit 已被設置為原來的 position,這意味著它包括以前讀到的所有字節,并且一個字節也不多。


4.10 ?第一次寫入

在第一次寫入時,我們從緩沖區中取四個字節并將它們寫入輸出通道。這使得 position 增加到 4,而 limit 不變,如下所示:

4.11 ?第二次寫入

我們只剩下一個字節可寫了。limit在我們調用 flip() 時被設置為 5,并且 position 不能超過 limit。所以最后一次寫入操作從緩沖區取出一個字節并將它寫入輸出通道。這使得position 增加到 5,并保持 limit 不變,如下所示:

4.12 ?clear

最后一步是調用緩沖區的clear() 方法。這個方法重設緩沖區以便接收更多的字節。 Clear 做兩種非常重要的事情:

1.它將 limit 設置為與 capacity 相同。

2.它設置 position 0

下圖顯示了在調用 clear() 后緩沖區的狀態:

緩沖區現在可以接收新的數據了。

對比rewind()clear()flip()函數

rewind()position置零,并清除標志位(mark)。它的作用在于為提取Buffer的有效數據做準備。

clear()也將position置零,同時將limit設置為capacity的大小,并清除標志位(mark)。由于清空了limit,因此便無法的值Buffer內哪些數據是真實有效的。這個方法用于為重新寫Buffer做準備。

flip()先將limit設置到position所在的位置,然后將position置為零,并清出標志位mark。它通常在讀寫轉換時使用。


rewind()

clear()

flip()

position

置零

置零

置零

mark

清空

清空

清空

limit

未改動

設置為capacity

設置為position

作用

為提取Buffer的有效數據做準備

為重新寫Buffer做準備

在讀寫轉換時使用


4.13 ?訪問方法

到目前為止,我們只是使用緩沖區將數據從一個通道轉移到另一個通道。然而,程序經常需要直接處理數據。例如,您可能需要將用戶數據保存到磁盤。在這種情況下,您必須將這些數據直接放入緩沖區,然后用通道將緩沖區寫入磁盤。

或者,您可能想要從磁盤讀取用戶數據。在這種情況下,您要將數據從通道讀到緩沖區中,然后檢查緩沖區中的數據。

在本節的最后,我們將詳細分析如何使用 ByteBuffer 類的 get() put() 方法直接訪問緩沖區中的數據。


4.14 ?get() 方法

ByteBuffer 類中有四個 get() 方法:

byte get();

ByteBuffer get( byte dst[] );

ByteBuffer get( byte dst[], intoffset, int length );

byte get( int index );

第一個方法獲取單個字節。第二和第三個方法將一組字節讀到一個數組中。第四個方法從緩沖區中的特定位置獲取字節。那些返回 ByteBuffer 的方法只是返回調用它們的緩沖區的 this 值。

此外,我們認為前三個get() 方法是相對的,而最后一個方法是絕對的。相對意味著 get() 操作服從 limit position 更明確地說,字節是從當前 position 讀取的,而 position get 之后會增加。另一方面,一個絕對方法會忽略 limit position 值,也不會影響它們。事實上,它完全繞過了緩沖區的統計方法。

上面列出的方法對應于ByteBuffer 類。其他類有等價的get() 方法,這些方法除了不是處理字節外,其它方面是是完全一樣的,它們處理的是與該緩沖區類相適應的類型。


4.15 ?put()方法

ByteBuffer 類中有五個 put() 方法:

ByteBuffer put( byte b );

ByteBuffer put( byte src[] );

ByteBuffer put( byte src[], intoffset, int length );

ByteBuffer put( ByteBuffer src);

ByteBuffer put( int index, byte b );

第一個方法寫入(put單個字節。第二和第三個方法寫入來自一個數組的一組字節。第四個方法將數據從一個給定的源 ByteBuffer 寫入這個 ByteBuffer。第五個方法將字節寫入緩沖區中特定的位置。那些返回 ByteBuffer 的方法只是返回調用它們的緩沖區的 this 值。

get() 方法一樣,我們將把 put() 方法劃分為相對或者絕對的。前四個方法是相對的,而第五個方法是絕對的。

上面顯示的方法對應于ByteBuffer 類。其他類有等價的put() 方法,這些方法除了不是處理字節之外,其它方面是完全一樣的。它們處理的是與該緩沖區類相適應的類型。


4.16 ?類型化的 get() put() 方法

除了前些小節中描述的get() put() 方法, ByteBuffer 還有用于讀寫不同類型的值的其他方法,如下所示:

getByte()

getChar()

getShort()

getInt()

getLong()

getFloat()

getDouble()

putByte()

putChar()

putShort()

putInt()

putLong()

putFloat()

putDouble()

事實上,這其中的每個方法都有兩種類型:一種是相對的,另一種是絕對的。它們對于讀取格式化的二進制數據(如圖像文件的頭部)很有用。

您可以在例子程序TypesInByteBuffer.java 中看到這些方法的實際應用。

// TypesInByteBuffer import java.io.*; import java.nio.*; import java.nio.channels.*; public class TypesInByteBuffer {static public void main( String args[] ) throws Exception {ByteBuffer buffer = ByteBuffer.allocate( 64 );buffer.putInt( 30 );buffer.putLong( 7000000000000L ); buffer.putDouble( Math.PI ); buffer.putInt( 40 );buffer.flip();//按照順序獲取—相對位置System.out.println( buffer.getInt() );System.out.println( buffer.getLong() ); System.out.println( buffer.getDouble() ); System.out.println( buffer.getInt() ); //按照順序獲取—絕對位置,與上面的結果一樣 System.out.println( buffer.getInt(0));//int類型為4byte System.out.println( buffer.getLong(4) );// long類型為4byte System.out.println( buffer.getDouble(12) );// double類型為4byte System.out.println( buffer.getInt(20) );} }

結果:

{"hb":[0,0,0,30,0,0,6,93,-48,-125,112,0,64,9,33,-5,84,68,45,24,0,0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"offset":0,"isReadOnly":false,"bigEndian":true,"nativeByteOrder":false,"mark":-1,"position":24,"limit":64,"capacity":64,"address":0}

30

7000000000000

3.141592653589793

40

30

7000000000000

3.141592653589793

40

4.17 ?緩沖區的使用:一個內部循環

下面的內部循環概括了使用緩沖區將數據從輸入通道拷貝到輸出通道的過程。

while (true) {buffer.clear();int r = fcin.read( buffer );if (r==-1) {break;}buffer.flip();fcout.write( buffer ); }

read() write() 調用得到了極大的簡化,因為許多工作細節都由緩沖區完成了。 clear() flip() 方法用于讓緩沖區在讀和寫之間切換。



轉載于:https://blog.51cto.com/qiangmzsx/1409627

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的NIO入门系列之第4章:缓冲区内部细节的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。