java NIO 就是NEW I O,他與傳統(tǒng)IO的最大的區(qū)分是 它是非阻塞IO。
Java NIO和IO之間的主要差別:
IO NIO 面向流 面向緩沖 阻塞IO 非阻塞IO 無 選擇器 |
他們各自適用于不同的環(huán)境,這里只簡單的說明其區(qū)分,具體的見博客:
http://ifeve.com/java-nio-vs-io/
NIO的核心api 是 Channel、Buffer和Selector,本品文章側(cè)重介紹前兩種。
首先舉1個簡單的例子進(jìn)行說明,這個例子使用NIO的api向1個文件中寫入數(shù)據(jù),然后把他讀出來打印,此例子的注釋很詳細(xì),可細(xì)細(xì)品味,另外有關(guān)NIO的概述可見譯文:
http://ifeve.com/channels/
官方文檔定義channel指“與1個實體的連接”,這個實體可以是1個裝備、文件、socket等。channel的接口定義本身簡單,JDK提供了幾種實現(xiàn)。
上圖展現(xiàn)了channel的體系,可見WritableByteChannel和ReadableByteChannel 分別擴(kuò)大了channel接口,加入了讀和寫的功能,其中最多見的實現(xiàn)已分別用紅色框起來,他們分別適用于不同的場合。
FileChannel 從文件中讀寫數(shù)據(jù),與fileinput/outputStream對應(yīng)
DatagramChannel 能通過UDP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。對應(yīng)DatagramSocket
SocketChannel 能通過TCP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。對應(yīng)IO中的socket
ServerSocketChannel可以監(jiān)聽新進(jìn)來的TCP連接,像Web服務(wù)器那樣。對每個新進(jìn)來的連接都會創(chuàng)建1個SocketChannel。對應(yīng)IO中ServerSocket
首先貼1張圖來表示Channel和Buffer的關(guān)系,即channel是通過buffer來讀寫數(shù)據(jù)的。關(guān)于buffer,http://ifeve.com/buffers/ ,以上地址翻譯的很好,這里摘出里面的部份內(nèi)容。
簡單的例子中,已說明了channel和buffer的基本用法這里,做個簡單的總結(jié),
使用Buffer讀寫數(shù)據(jù)1般遵守以下4個步驟:
1. 寫入數(shù)據(jù)到Buffer
2. 調(diào)用flip()方法
3. 從Buffer中讀取數(shù)據(jù)
4. 調(diào)用clear()方法或compact()方法
當(dāng)向buffer寫入數(shù)據(jù)時,buffer會記錄下寫了多少數(shù)據(jù)。1旦要讀取數(shù)據(jù),需要通過flip()方法將Buffer從寫模式切換到讀模式。在讀模式下,可以讀取之前寫入到buffer的所有數(shù)據(jù)。
1旦讀完了所有的數(shù)據(jù),就需要清空緩沖區(qū),讓它可以再次被寫入。有兩種方式能清空緩沖區(qū):調(diào)用clear()或compact()方法。clear()方法會清空全部緩沖區(qū)。compact()方法只會清除已讀過的數(shù)據(jù)。任何未讀的數(shù)據(jù)都被移到緩沖區(qū)的起始處,新寫入的數(shù)據(jù)將放到緩沖區(qū)未讀數(shù)據(jù)的后面。
buffer有3個基本的屬性capacity limit position.
capacity 是指buffer的大小,在buffer建立的時候已肯定。
limit 當(dāng)buffer處于寫模式,指還可以寫入多少數(shù)據(jù),處于讀模式,指還有多少數(shù)據(jù)可以讀。
position 當(dāng)buffer處于寫模式,指下1個寫數(shù)據(jù)的位置, 處于讀模式,當(dāng)前將要讀取的數(shù)據(jù)的位置。每讀寫1個數(shù)據(jù),position+1
也就是 limit 和position在 buffer的讀/寫時的含義不1樣。當(dāng)調(diào)用buffer的flip方法,由寫模式變成讀模式時,
limit(讀)=position(寫)
position(讀) =0;
buffer有多種類型,不同的buffer提供不同的方式操作buffer中的數(shù)據(jù)。
寫數(shù)據(jù)到buffer有兩種情況:
1. 從channel寫到 buffer,如例子中channel從文件中讀取數(shù)據(jù),寫到channel
2. 直接調(diào)用put方法,往里面寫數(shù)據(jù)
這個操作已解釋過,轉(zhuǎn)換buffer為讀模式
從Buffer中讀取數(shù)據(jù)有兩種方式:
1. 從Buffer讀取數(shù)據(jù)到Channel。
2. 使用get()方法從Buffer中讀取數(shù)據(jù)。
Buffer.rewind()將position設(shè)回0,所以你可以重讀Buffer中的所有數(shù)據(jù)。limit保持不變,依然表示能從Buffer中讀取多少個元素(byte、char等)。
1旦讀完Buffer中的數(shù)據(jù),需要讓Buffer準(zhǔn)備好再次被寫入。可以通過clear()或compact()方法來完成。
如果調(diào)用的是clear()方法,position將被設(shè)回0,limit被設(shè)置成 capacity的值。換句話說,Buffer 被清空了。Buffer中的數(shù)據(jù)并未清除,只是這些標(biāo)記告知我們可以從哪里開始往Buffer里寫數(shù)據(jù)。
如果Buffer中有1些未讀的數(shù)據(jù),調(diào)用clear()方法,數(shù)據(jù)將“被遺忘”,意味著不再有任何標(biāo)記會告知你哪些數(shù)據(jù)被讀過,哪些還沒有。
如果Buffer中仍有未讀的數(shù)據(jù),且后續(xù)還需要這些數(shù)據(jù),但是此時想要先先寫些數(shù)據(jù),那末使用compact()方法。
compact()方法將所有未讀的數(shù)據(jù)拷貝到Buffer起始處。然后將position設(shè)到最后1個未讀元素正后面。limit屬性仍然像clear()方法1樣,設(shè)置成capacity。現(xiàn)在Buffer準(zhǔn)備好寫數(shù)據(jù)了,但是不會覆蓋未讀的數(shù)據(jù)。上一篇 康托展開
下一篇 【HTML】表格標(biāo)記