Java - NIO之Buffer(下)
九、壓縮
如果從Buffer中讀取了一部分資料之後仍有部分未讀的資料,且後續還需要這些資料,但是此時想要先再寫些資料,那麼使用壓縮
/**
* 準備資料
*/
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put((byte)'M').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'w');
/**
* 翻轉模式
*/
buffer.flip();
/**
* 釋放一部分('M'和'e'),剩下的保留
*/
for (int i = 0; i < 2; i++) {
System.out.print((char)buffer.get());
}
/**
* 釋放之後,進行壓縮(自動翻轉為寫的模式)
*/
buffer.compact();
/**
* 在剩下的部分的後面繼續填充
*/
buffer.put((byte)'s');
/**
* 翻轉模式
*/
buffer.flip();
System.out.println();
while (buffer.hasRemaining()) {
System.out.print((char)buffer.get());
}
需要注意的是:當執行釋放一部分('M'和'e')之後,如圖:
而執行compact()壓縮操作,將所有未讀的資料拷貝到Buffer起始處(第一個未讀元素的索引為0),同時翻轉為寫模式,並將當前的位置(position)指定到未讀資料元素的末尾,如下圖所示:"llow"被拷貝,開始的'l'索引為0,position指向"llow"之後,至於位置4和5中對應的'o'和'w',因為現在正在或已經超出了當前位置,所以是死的,會被之後的put()所重寫。
十、清理
呼叫的clear()之後,position將被設回0,limit被設定成 capacity的值。換句話說,Buffer 被清空了。Buffer中的資料並未清除,只是這些標記告訴我們可以從哪裡開始往Buffer裡寫資料。如果Buffer中有一些未讀的資料,呼叫clear()方法,資料將“被遺忘”,意味著不再有任何標記會告訴你哪些資料被讀過,哪些還沒有。
十一、Buffer比較之equals
兩個緩衝區被認為相等的充要條件是:
兩個物件型別相同。包含不同資料型別的buffer永遠不會相等,而且buffer絕不會等於非buffer物件
兩個物件都剩餘同樣數量的元素(Buffer的容量不需要相同,而且緩衝區中剩餘資料的索引也不必相同;但每個緩衝區中剩餘元素的數目(從位置到上界)必須相同)
在每個緩衝區中應被get()函式返回的剩餘資料元素序列必須一致
/**
* 準備資料
*/
ByteBuffer buffer1 = ByteBuffer.allocate(10);
buffer1.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o'); //寫入Hello
ByteBuffer buffer2 = ByteBuffer.allocate(12);
buffer2.put((byte)'A').put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'Y'); //寫入AHelloY
/**
* 結果為true
* 因為1和2型別都為byte, 都還有5的空餘(l-p)且空餘的都是沒有被填充的byte
* 所以比較的結果跟讀寫的模式也有關係
*/
System.out.println(buffer1.equals(buffer2));
buffer1.flip();
buffer2.flip();
/**
* 結果為false
*/
System.out.println(buffer1.equals(buffer2));
/* p移動到H的位置 */
buffer2.get();
/* l設定為Y的位置(不包含Y了) */
buffer2.limit(6);
/**
* 結果為true
*/
System.out.println(buffer1.equals(buffer2));
十二、Buffer比較之compareTo
CompareTo是針對每個緩衝區內剩餘資料進行的,與它們在equals()中的方式相同,直到不相等的元素被發現或者到達緩衝區的上界。如果一個緩衝區在不相等元素髮現前已經被耗盡,較短的緩衝區被認為是小於較長的緩衝區。
/**
* 準備資料
*/
ByteBuffer buffer1 = ByteBuffer.allocate(10);
buffer1.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o'); //寫入hello
ByteBuffer buffer2 = ByteBuffer.allocate(12);
buffer2.put((byte)'A').put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o').put((byte)'Y'); //寫入AHelloY
/**
* 結果:0
*/
System.out.println(buffer1.compareTo(buffer2));
buffer1.flip();
buffer2.flip();
/**
* 結果:7
*/
System.out.println(buffer1.compareTo(buffer2));
/* p移動到H的位置 */
buffer2.get();
/* l設定為Y的位置(不包含Y了) */
buffer2.limit(6);
/**
* 結果:0
*/
System.out.println(buffer1.compareTo(buffer2));
十三、批量讀寫
如果所要求的數量的資料不能被傳送,那麼不會有資料被傳遞,緩衝區的狀態保持不變,同時丟擲BufferUnderflowException異常。
/**
* 準備資料
*/
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o');
buffer.flip();
/**
* 等價為buffer.get(byteArr,0,byteArr.length);但是buffer不能提供byteArr長度的資料,所以BufferUnderflowException異常
*/
byte[] byteArr = new byte[10];
buffer.get(byteArr);
/**
* 可以通過,buffer的狀態將改變
*/
byte[] byteSmall = new byte[3];
buffer.get(byteSmall);
如果您想將一個小型緩衝區傳入一個大型陣列,您需要明確地指定緩衝區中剩餘的資料長度;如果緩衝區存有比陣列能容納的數量更多的資料,您可以重複利用陣列讀取。
/**
* 準備資料
*/
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put((byte)'H').put((byte)'e').put((byte)'l').put((byte)'l').put((byte)'o'); //寫入hello
buffer.flip();
/**
* 小緩衝區資料傳入大型資料
*/
byte [] bigArray = new byte [15];
// 通過remaining()獲取緩衝區剩餘的量
int length = buffer.remaining();
// 指定獲取的量
buffer.get(bigArray, 0, length);
for (int i = 0; i < bigArray.length; i++) {
System.out.print((char)bigArray[i]);
}
System.out.println("-------------------");
/**
* 重置位置,為測試方便
*/
buffer.position(0);
/**
* 大緩衝區資料到小陣列
*/
byte[] smallArray = new byte[2];
// 迴圈從buffer中讀取
while (buffer.hasRemaining()) {
// smallArray長度的範圍內,buffer最多還能提供多少量的資料
int slength = Math.min(buffer.remaining(), smallArray.length);
// 從Buffer中讀取
buffer.get(smallArray, 0, slength);
//對獲取的資料執行處理
for (int i = 0; i < smallArray.length; i++) {
System.out.print((char)smallArray[i]);
//清空已經處理的位置
smallArray[i] = 0;
}
}
補充:put是類似的;另外,dstBuffer.put(srcBuffer);是兩個緩衝區之前的傳遞,如果成功,兩個緩衝區的狀態都將改變
十四、複製緩衝區
使用duplicate()用於建立一個與原始緩衝區相似的新緩衝區。
兩個緩衝區共享資料元素,擁有同樣的容量,但每個緩衝區擁有各自的位置,上界和標記屬性,但初始時是一樣的。複製一個緩衝區會建立一個新的Buffer物件,但並不複製資料。原始緩衝區和副本都會操作同樣的資料元素。
/**
* 準備資料
*/
CharBuffer buffer = CharBuffer.allocate (8);
buffer.put("abcdefgh");
/**
* 執行之後,buffer的c為8,p為5,m為3,l為6
*/
buffer.position(3).limit(6).mark().position (5);
//
/**
* 執行之後,dupeBuffer的c,p,m,l和buffer一樣
*/
CharBuffer dupeBuffer = buffer.duplicate();
//
/**
* 複製完成之後,各自維護一份自己的四大c,p,m,l屬性
*/
buffer.position(2);
dupeBuffer.position(4);
十五、分割緩衝區
使用slice()用於建立一個從原始緩衝區的當前位置開始的新緩衝區,並且其容量是原始緩衝區的剩餘元素數量(limit-position)
這個新緩衝區與原始緩衝區共享一段資料元素子序列。分割出來的緩衝區也會繼承只讀和直接屬性
/**
* 準備資料
*/
CharBuffer buffer = CharBuffer.allocate (8);
buffer.put("abcdefgh");
/**
* 設定屬性
*/
buffer.position(2).limit(5);
/**
* 分割
*/
CharBuffer sliceBuffer = buffer.slice();
/**
* sliceBuffer只含有'c'、'd'和'e'
*/
for (int i = 0; sliceBuffer.hasRemaining(); i++) {
System.out.print(sliceBuffer.get());
}
/**
* 修改 sliceBuffer的一個資料
*/
sliceBuffer.put(0, 'z');
sliceBuffer.flip();
System.out.println("");
/**
* 'z'、'd'和'e'
*/
while(sliceBuffer.hasRemaining()){
System.out.print((char)sliceBuffer.get());
}
System.out.println("");
buffer.position(0).limit(8);
/**
* a b z d e f g h
*/
while(buffer.hasRemaining()){
System.out.print((char)buffer.get());
}
十六、CharBuffer兩個特殊的方法
CharBuffer cb = CharBuffer.allocate(10);
String str = "abcdefgh";
/**
* 填充整個String字串
*/
cb.put(str);
cb.flip();
/**
* a b c d e
*/
while (cb.hasRemaining()) {
System.out.print(cb.get());
}
cb.clear();
/**
* 填充String字串中指定的開始和結束之間的字元
* str中第1到第3的字元 start -- end-1
*/
cb.put(str, 1, 4);
cb.flip();
System.out.println();
/**
* b c d
*/
for (int i = 0; cb.hasRemaining(); i++) {
System.out.print(cb.get());
}
附:ByteBuffer轉String的方法
public static String getString(ByteBuffer buffer) {
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
try {
charset = Charset.forName("UTF-8");
decoder = charset.newDecoder();
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
}
相關文章
- Java NIO之BufferJava
- Java NIO之Buffer的使用Java
- JAVA NIO BufferJava
- Java NIO - BufferJava
- Java NIO 之 Buffer(緩衝區)Java
- Java-NIO之Buffer(緩衝區)Java
- Java NIO:Buffer、Channel 和 SelectorJava
- BIO到NIO原始碼的一些事兒之NIO 下 Buffer解讀 下原始碼
- Java NIO學習系列一:BufferJava
- Nio再學習之NIO的buffer緩衝區
- BIO到NIO原始碼的一些事兒之NIO 下 Buffer解讀 上原始碼
- java.nio.Buffer.filp()方法的用法詳解Java
- NIO(五)Buffer總結
- Java NIO之SelectorJava
- Java Socket 之 NIOJava
- Java IO之NIOJava
- Java NIO 之 Channel(通道)Java
- Java-NIO之SelectorJava
- 【譯】Java NIO 簡明教程系列之 NIO 概述Java
- Java NIO之Scatter和GatherJava
- Java NIO 之緩衝區Java
- Java-NIO之Channel(通道)Java
- 【NIO】Buffer、Channel、Selector 關係小結
- 【譯】Java NIO 簡明教程系列之 NIO 簡介Java
- Java網路程式設計與NIO詳解4:淺析NIO包中的Buffer、Channel 和 SelectorJava程式設計
- Java NIO之Selector(選擇器)Java
- 初識NIO之Java小DemoJava
- BIO到NIO原始碼的一些事兒之NIO 下 之 Selector原始碼
- Java NIO之擁抱Path和FilesJava
- Java網路程式設計與NIO詳解8:淺析mmap和Direct BufferJava程式設計
- Java NIOJava
- 【譯】Java NIO 簡明教程系列之 ChannelJava
- Java NIO 系列文章之 淺析Reactor模式JavaReact模式
- IO之核心buffer----"buffer cache"
- JAVA 探究NIOJava
- Java NIO SocketChannelJava
- Java NIO - 群聊Java
- Java NIO:通道Java
- Java NIO filesJava