在 NIO 庫(kù)中,所有數(shù)據(jù)都是用緩沖區(qū)處理的。在讀取數(shù)據(jù)時(shí),它是直接讀到緩沖區(qū)中的。在寫(xiě)入數(shù)據(jù)時(shí),它是寫(xiě)入到緩沖區(qū)中的。任何時(shí)候訪問(wèn) NIO 中的數(shù)據(jù),都是將它放到緩沖區(qū)中。緩沖區(qū)實(shí)質(zhì)上是一個(gè)數(shù)組。通常它是一個(gè)字節(jié)數(shù)組,但是也可以使用其他種類(lèi)的數(shù)組。但是一個(gè)緩沖區(qū)不
僅僅
是一個(gè)數(shù)組。緩沖區(qū)提供了對(duì)數(shù)據(jù)的結(jié)構(gòu)化訪問(wèn),而且還可以跟蹤系統(tǒng)的讀/寫(xiě)進(jìn)程。
buffer其實(shí)只是一個(gè)美化了的
數(shù)組
。
狀態(tài)變量
跟蹤數(shù)據(jù)的狀態(tài)情況使buffer可以自己管理數(shù)據(jù)資源
position
: 其實(shí)是指從buffer讀取或?qū)懭隻uffer的下一個(gè)元素位置。比如,已經(jīng)寫(xiě)入buffer 3個(gè)元素那那么position就是指向第4個(gè)位置,即position設(shè)置為3(數(shù)組從0開(kāi)始計(jì))。
limit
:還有多少數(shù)據(jù)需要從buffer中取出,或還有多少空間可以放入。postition總是<=limit。
capacity
: 表示buffer本身底層數(shù)組的容量。limit絕不能>capacity。
filp():
作了兩件事情:
1.將limit指向現(xiàn)在position的位置 2.將position設(shè)置為0 (limit=position;position=0)
??
????這個(gè)過(guò)程可以使之前buffer寫(xiě)入數(shù)據(jù)時(shí)改變的狀態(tài)變?yōu)榭梢浴皽?zhǔn)備讀取”。因?yàn)橹皩?xiě)到buffer中的數(shù)據(jù)就是position 到 limit-1 兩個(gè)位置之間(limit指向最后一個(gè)數(shù)據(jù)的后一個(gè)位置)。
clear():
???
也作了兩件事:1. limit=capacity 2.position=0
這個(gè)過(guò)程可以使buffer讀取數(shù)據(jù)時(shí)改變的狀態(tài)改變?yōu)椤扒蹇詹?zhǔn)備寫(xiě)入”。
訪問(wèn)方法
以下都以bytebuffer為例
get():
???前三個(gè)get方法是相對(duì)讀取。就是相對(duì)于位置狀態(tài)來(lái)讀取數(shù)據(jù),并且會(huì)改變position位置狀態(tài)。
???byte get();
???ByteBuffer get(byte dst[]);//讀取bytebuffer中數(shù)據(jù)寫(xiě)入 dst[]
???ByteBuffer get(byte dst[],int offset, int length);
???
???該讀取數(shù)據(jù)是絕對(duì)讀取(一個(gè)byte),即會(huì)忽略limit和position值。并完全繞過(guò)了緩沖區(qū)的狀態(tài)統(tǒng)計(jì)方法。
???就是說(shuō)不會(huì)改變buffer內(nèi)部的位置狀態(tài)。
???byte get(int index);
?
put();
???與get類(lèi)似 前四個(gè)put方法是相對(duì)讀取。即受position 以及l(fā)imit影響,并且會(huì)改變 position。
???ByteBuffer put( byte b );
???ByteBuffer put( byte src[] ); //從src[]寫(xiě)入bytebuffer
???ByteBuffer put( byte src[], int offset, int length );
???ByteBuffer put( ByteBuffer src );
???最后一個(gè)是絕對(duì)寫(xiě)入 不會(huì)影響position等位置狀態(tài)。
???ByteBuffer put( int index, byte b );
?
除了byte的讀寫(xiě)還有其他類(lèi)型的讀寫(xiě)方法。并且他們都存在
相對(duì)以及絕
對(duì)兩類(lèi)。
?
操作的典型使用:
while (true) {
???? buffer.clear(); // 準(zhǔn)備將數(shù)據(jù)寫(xiě)入buffer
???? int r = fcin.read( buffer ); // channel讀取外部系統(tǒng)的數(shù)據(jù)并寫(xiě)入 buffer
???? if (r==-1) {
?????? break;
???? }
???? buffer.flip(); //準(zhǔn)備將數(shù)據(jù)讀出buffer
???? fcout.write( buffer ); // channel讀取buffer的數(shù)據(jù)并寫(xiě)到相應(yīng)的外部系統(tǒng)
}
高級(jí)應(yīng)用
緩存區(qū)的分配和包裝
ByteBuffer.allocate(int);方法可以分配(創(chuàng)建)一個(gè)byte類(lèi)型的buffer。
ByteBuffer.wrap(byte[]);方法可以將一個(gè)已有的byte數(shù)組包裝出一個(gè)新的bytebuffer對(duì)象。
后一種方式需要小心處理原來(lái)的那個(gè)byte數(shù)組。因?yàn)樗梢灾苯釉L問(wèn)了。
緩沖區(qū)的分片
分片就是建立“子緩沖區(qū)”。子緩沖區(qū)共享父緩沖區(qū)的一部分底層數(shù)組位置。
在某種意義上,子緩沖區(qū)就像原來(lái)的緩沖區(qū)中的一個(gè)窗口。
這樣當(dāng)改變子緩沖區(qū)的內(nèi)容時(shí),父緩沖區(qū)的相應(yīng)位置也會(huì)被改變。
分片操作是根據(jù)當(dāng)前position以及l(fā)imit的值來(lái)確定的。
buffer.position( 3 );
buffer.limit( 7 );
ByteBuffer slice = buffer.slice();
只讀緩沖區(qū)
asReadOnlyBuffer()方法可以返回一個(gè)與原buffer對(duì)象一樣的對(duì)象,只是新的buffer對(duì)象是只讀的。
直接緩沖區(qū)
sun的定義:給定一個(gè)直接字節(jié)緩沖區(qū),Java 虛擬機(jī)將盡最大努力直接對(duì)它執(zhí)行本機(jī) I/O 操作。也就是說(shuō),它會(huì)在每一次調(diào)用底層操作系統(tǒng)的本機(jī) I/O 操作之前(或之后),嘗試避免將緩沖區(qū)的內(nèi)容拷貝到一個(gè)中間緩沖區(qū)中(或者從一個(gè)中間緩沖區(qū)中拷貝數(shù)據(jù))。
創(chuàng)建directbuffer的方式是用
ByteBuffer.allocateDirect( int )
;方法替代ByteBuffer.allocate(int);
內(nèi)存影射文件I/O
它讀寫(xiě)要比其他IO快很多.
他使文件或文件的一部分由內(nèi)存影射。但是只有操作該部分位置的數(shù)據(jù)才是以?xún)?nèi)存方式讀寫(xiě)的,而不是整個(gè)文件讀入內(nèi)存。(并且他是一個(gè)os的底層機(jī)制。由os底層異步完成內(nèi)存與物理磁盤(pán)上的數(shù)據(jù)同步)
影射文件可以通過(guò)FileChannel對(duì)象的map方法得到。
比如以下就是將一個(gè)文件的前1024個(gè)字節(jié)影射到內(nèi)存,并創(chuàng)建一個(gè)MappedByteBuffer對(duì)象返回出來(lái)。MappedByteBuffer是ByteBuffer的一個(gè)子類(lèi)。
MappedByteBuffer mbb = fc.map( FileChannel.MapMode.READ_WRITE, start, size );
?
Java NIO ByteBuffer