JDK 1.4的java.nio.*包中引入了新的JavaI/O類庫,其目的在于提高速度。(實(shí)際上,舊的I/O包已經(jīng)使用nio重新實(shí)現(xiàn)過,以便充分利用這種速度,即使我們不顯式地用nio編寫代碼,也能從中受益! nio速度的提高來自于所使用的結(jié)構(gòu)更接近于操作系統(tǒng)執(zhí)行I/O的方式(Java執(zhí)行I/O接近于操作系統(tǒng)執(zhí)行I/O,所以速度得到了提高):通道和緩沖器。我們可以把它想象成一個煤礦,通道是一個包含煤層(數(shù)據(jù))的礦藏,而緩沖器則是派送到礦藏的卡車。卡車載滿煤炭而歸,我們再從卡車上獲得煤炭。也就是說,我們要讀書到數(shù)據(jù),并沒有直接和通道交互;只是和緩沖器交互,并把緩沖器派送到通道。通道要么從緩沖器獲得數(shù)據(jù),要么向緩沖器發(fā)送數(shù)據(jù)! 唯一直接與通道交互的緩沖器是ByteBuffer,它是java.nio里面的類:通過告知分配多少存儲空間來創(chuàng)建一個ByteBuffer對象,并且還有一個方法選擇集,用以原始的字節(jié)形式或基本數(shù)據(jù)類型輸出和讀取數(shù)據(jù)。但是沒辦法輸出或讀取對象,即使是字符串對象也不行; ByteBuffer是一個抽象類,不能直接創(chuàng)建實(shí)例,可以調(diào)用該類的static方法allocate(int capacity)來創(chuàng)建它的一個新緩沖區(qū),該緩沖區(qū)的位置將為零,其界限將為其容量,其標(biāo)記是不確定的。它將具有一個底層實(shí)現(xiàn)數(shù)組,且其 數(shù)組偏移量將為零。 關(guān)于通道,這里介紹一個文件通道FileChannel,它也是一個抽象類,也不能直接創(chuàng)建實(shí)例。舊的I/O類庫中有本個類被修改過了,可以用它們的getChannel()來返回一個FileChannel對象(更確切的說應(yīng)該是返回FileChannel的一個匿名子類的對象)。這三個能返回FileChannel的類是:FileInputStream,FileOutputStream,RandomAccessFile 。值得注意的是它們都是字節(jié)流的,Reader與Writer這兩個處理字符流的類不能用于通道,不過java,nio.channels.Channels類提供了實(shí)用方法,用以在通道中產(chǎn)生Reader與Writer(想了解更多請查API文檔,這里不介紹)! 緩沖區(qū)的容量 是它所包含的元素的數(shù)量。緩沖區(qū)的容量不能為負(fù)并且不能更改。 緩沖區(qū)的限制 是第一個不應(yīng)該讀取或?qū)懭氲脑氐乃饕>彌_區(qū)的限制不能為負(fù),并且不能大于其容量。 緩沖區(qū)的位置 是下一個要讀取或?qū)懭氲脑氐乃饕?。緩沖區(qū)的位置不能為負(fù),并且不能大于其限制。 因此,我們從緩沖區(qū)讀書數(shù)據(jù),其實(shí)是從此緩沖區(qū)的“位置”處一直讀到“限制”處!
remind(),重繞此緩沖區(qū),將位置設(shè)置為 0 并丟棄標(biāo)記。此方法與flip()的區(qū)別是:remind()不會把限制設(shè)置為當(dāng)前位置,而是保持限制不變!與clear()的區(qū)別是:remind()不會把限制設(shè)置為容量,而是保持限制不變! ========================================================================================== //例一: public class GetChannel { //進(jìn)行此操作后,buff的位置移動了從FileChannel中讀取的字節(jié)個數(shù)! buff.flip(); //為下面的buff.get()做準(zhǔn)備,將buff的限制設(shè)置為當(dāng)前位置,然后將位置設(shè)置為 0 // Copying a file using channels and buffers public class ChannelCopy { //其實(shí)此循環(huán)只會執(zhí)行一次,因?yàn)閳?zhí)行一次就會把FileChannel中的全部數(shù)據(jù)都讀到buffer中
============================啟示================================ 當(dāng)對flip(),clear(),remind()不是很理解而正在考慮某個地方是否需要這三個方法時,我們還可以調(diào)用limit(),position(),remainning()等方法來進(jìn)行調(diào)試。 public final int limit()
public final int position()
====================================================================== 上面的兩個例子,是因?yàn)橛蠪ileChannel的read()或者write(),以至把ByteBuffer中的位置移動了相應(yīng)的字節(jié)數(shù)。然后調(diào)用flip時,就把限制設(shè)置為當(dāng)前位置。此時的position就不為0了。下面的例子中,沒有FileChannel的參與,當(dāng)前位置也就沒有了變化,此時,若再調(diào)用flip,由于當(dāng)前位置是0,設(shè)置為限制后,限制也變成0,若我們要從限制為0的ByteBuffer中讀取數(shù)據(jù),此時就什么也沒讀到,可能還會拋出異常。那么解決的方法就是調(diào)用rewind(),此方法,只是把位置設(shè)置為0,而不會改變其限制,這時,限制就仍為容量。因?yàn)橛?font color=#0000ff>ByteBuffer的static allocated()時,新緩沖區(qū)的位置將為零,其限制將為其容量! 另外,調(diào)用ByteBuffer的get()與put()時,會把position移動一個字節(jié)!而調(diào)用這兩個方法的帶參數(shù)版本則不會改變position的值,這里還要區(qū)別一下兩種情況的put方法: 情況一: ByteBuffer bb = ByteBuffer.allocate(1024); cb.put("Hwdy!"); ////字符串中的每個字符占1個字節(jié)!共占5個字節(jié)!所以此句會使position移動5個字節(jié)!
=================================================================== 情況二: ByteBuffer bb = ByteBuffer.allocate(BSIZE); print(bb.position()); //所以此處的postion值為0 |
|