摘要:通過協議向網絡讀寫數據通過協議向網絡讀寫數據以一個服務器的形式,監聽到來的連接,對每個連接建立一個。
Java NIO 教程 NIO是什么?
它是Java1.4之后出現的IO API,與傳統IO和網絡API不同,具有非阻塞的特點。
在BIO中我們使用字節流和字符流。NIO中我們使用channel和buffer。數據總是從一個channel中讀取到buffer中,或者從buffer中寫入到channel中。
NIO的意思是一個線程可以讓一個channel將數據讀取到buffer中,與此同時,這個線程還可以做其他的事情,線程可以等到數據全部進入buffer之后再處理數據,從buffer中寫入線程也是一樣的。
selector:選擇器是一個NIO當中的概念,指的是一個對象,能監視多個channel發生的事件(如連接建立,數據到達等)。因此,一個單線程可以監視多個channel的數據。
Java NIO 總覽Java NIO的三個核心基礎組件,
Channels
Buffers
Selectors
其余的諸如Pipe,FileLcok都是在使用以上三個核心組件時幫助更好使用的工具類。
Channels和Buffers的關系所有的IO操作在NIO中都是以Channel開始的。一個Channel就像一個流。從Channel中,數據可以被讀取到buffer里,也可以從buffer里寫到Channel中。
基本的Channel實現有以下這些:
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
涵蓋了UDP,TCP以及文件的IO操作。
核心的buffer實現有這些
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
涵蓋了所有的基本數據類型(4類8種,除了Boolean)。也有其他的buffer如MappedByteBuffer,此處不講。
selectorsselector允許一個線程來監視多個Channel,這在當你的應用建立了多個連接,但是每個連接吞吐量都較小的時候是可行的。例如:一個聊天服務器。圖為一個線程使用selector處理三個channel。
要使用一個Selector,你要先注冊這個selector的Channels。然后你調用selector的select()方法。這個方法會阻塞,直到它注冊的channels當中有一個準備好了的事件發生了。當select()方法返回的時候,線程可以處理這些事件,如新的連接的到來,數據收到了等。
NIO ChannelsNIO channel和流很近似但是也有一些不同。
你既可以讀取也可以寫入到channel,流只能讀取或者寫入,inputStream和outputStream。
channel可以異步地讀和寫。
channel永遠都是從一個buffer中讀或者寫入到一個buffer中去。
channel的實現以下是NIO中最重要的幾個channel的實現。
FileChannel 向文件當中讀寫數據。
DatagramChannel 通過UDP協議向網絡讀寫數據
SocketChannel 通過TCP協議向網絡讀寫數據
ServerSocketChannel 以一個web服務器的形式,監聽到來的TCP連接,對每個連接建立一個SocketChannel。
一個簡單的channel例子使用一個FileChannel將數據讀入一個buffer
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); while (bytesRead != -1) { System.out.println("Read " + bytesRead); buf.flip(); while(buf.hasRemaining()){ System.out.print((char) buf.get()); } buf.clear(); bytesRead = inChannel.read(buf); } aFile.close();
buf.flip()的意思是讀寫轉換,首先你讀入一個buffer,然后你flip,轉換讀寫,然后再從buffer中讀出,buffer的操作接下來會講。
NIO bufferNIO buffer在與NIO Channel交互時使用,數據從channel中讀取出來放入buffer,或者從buffer中讀取出來寫入channel。
buffer就是一塊內存,你可以寫入數據,并且在之后讀取它。這塊內存被包裝成NIO buffer對象,它提供了一些方法來讓你更簡單地操作內存。
buffer的基本使用使用buffer讀寫數據基本上分為以下4部操作:
將數據寫入buffer
調用buffer.flip()
將數據從buffer中讀取出來
調用buffer.clear()或者buffer.compact()
在寫buffer的時候,buffer會跟蹤寫入了多少數據,需要讀buffer的時候,需要調用flip()來將buffer從寫模式切換成讀模式,讀模式中只能讀取寫入的數據,而非整個buffer。
當數據都讀完了,你需要清空buffer以供下次使用,可以有2種方法來操作:
調用clear()
調用compact()
區別:clear方法清空整個buffer,compact方法只清除你已經讀取的數據,未讀取的數據會被移到buffer的開頭,此時寫入數據會從當前數據的末尾開始。
一個簡單的buffer使用例子:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); //創建一個容量為48的ByteBuffer ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); //從channel中讀(取數據然后寫)入buffer //下面是讀取buffer while (bytesRead != -1) { buf.flip(); //轉換buffer為讀模式 while(buf.hasRemaining()){ System.out.print((char) buf.get()); // 一次讀取一個byte } buf.clear(); //清空buffer準備下一次寫入 bytesRead = inChannel.read(buf); } aFile.close();buffer的Capacity,Position和Limit
buffer有3個屬性需要熟悉以理解buffer的工作原理:
容量(Capacity):緩沖區能夠容納的數據元素的最大數量。容量在緩沖區創建時被設定,并且永遠不能被改變。
上界(Limit):寫模式中等價于buffer的大小,即capacity;讀模式中為當前緩沖區中一共有多少數據,即可讀的最大位置。這意味著當調用filp()方法切換成讀模式時,limit的值變成position的值,而position重新指向0.
位置(Position):下一個要被讀或寫的元素的位置。初始化為0,buffer滿時,position最大值為capacity-1。切換成讀模式的時候,position指向0。Position會自動由相應的 get( )和 put( )函數更新。
position和limit的值在讀/寫模式中是不一樣的。
capacity的值永遠表示buffer的大小。
下圖解釋了在讀/寫模式中Capacity,Position和Limit的意思。
buffer的種類Java NIO中有以下這些buffer種類:
ByteBuffer
MappedByteBuffer //比較特殊,會在以后講解
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
創建一個buffer獲得一個buffer 之前必須先分配一塊內存,每個buffer類都有一個靜態方法allocate() 來做這件事。
下例為創建一個容量為48byte的ByteBuffer:
ByteBuffer buf = ByteBuffer.allocate(48);
創建一個1024個字符的CharBuffer
CharBuffer buf = CharBuffer.allocate(1024);
寫入buffer的方法有2種:
1.從一個channel中寫入buffer。
2.調用buffer的put()方法來自行寫入數據。
例:
int bytesRead = inChannel.read(buf); //從channel讀入buffer
buf.put(127); //自行寫入buffer
put方法有很多的重載形式。以供你用各種不同的方法寫入buffer中,比如從一個特定的position,或者寫入一個array,詳見JavaDoc。
flip()flip方法將寫模式切換成讀模式,調用flip()方法會將limit設置為position,將position設置回0。
換句話說,position標志著寫模式中寫到哪里,切換成讀模式之后,limit標志著之前寫到哪里,也就是現在能讀到哪里。
從buffer中讀取數據有2種方法可以從buffer中讀取數據。
1.從buffer中讀取數據到channel中。
2.使用buffer的get()方法自行從buffer中讀出數據。
例子:
//從buffer中讀取數據到channel中 int bytesWritten = inChannel.write(buf); //使用buffer的get()方法自行從buffer中讀出數據 byte aByte = buf.get();
get方法有很多的重載形式。以供你用各種不同的方法讀取buffer中的數據。例如從特定位置讀取數據,或者讀一個數組出來。詳見JavaDoc。
rewind()rewind()方法將position設置為0,但是不會動buffer里的數據,這樣可以從頭開始重新讀取數據,limit的值不會變,這意味著limit依舊標志著能讀多少數據。
clear()和compact()當你讀完所有的數據想要重新寫入數據時,你可以調用clear或者compact方法。
當你調用clear()方法的時候,position被設置為0,limit被設置為capacity,換句話說,buffer的數據雖然都還在,但是buffer被初始化了,處于可以被重寫的狀態。
這也就意味著如果buffer中還有沒被讀取的數據,在執行clear之后,你無法知道數據讀到哪兒了,剩下的數據還有多少。
如果還有沒有讀完的數據,但是你想先寫數據,可以用compact()方法,這樣未讀數據會放在buffer前端,可以在未讀數據之后跟著寫新的數據。compact()會復制未讀數據到buffer前端,然后設置position為未讀數據單位后面緊跟的位置。limit還是設置為capacity,這和clear是一樣的。現在buffer處于可以寫的狀態,但是不會覆蓋之前未讀完的數據。
mark()和reset()你可以通過調用buffer.mark()來mark一個buffer中給定的位置。然后你就可以用buffer.reset()方法來講position設置回之前mark的位置。
例子:
buffer.mark(); //調用buffer.get()方法若干次,e.g. 比如在做parsing的時候 buffer.reset(); //set position back to mark.equals() 和 compareTo()
使用這2種方法能夠比較2個buffer。
equals()
equals()方法用于判斷2個buffer是否相等,2個buffer是equal的,當它們:
是同一種數據類型的buffer。
buffer中未讀取的bytes,chars等數據個數是一樣的,即(limit-position)相等,capacity不需要相等,剩余數據的索引也不需要相等。
未讀取的bytes,chars等內容是一模一樣的,即各自[position,limit-1]索引的數據要完全相等。
如你所見,equals()方法只比較buffer的部分內容,而不是buffer中所有的數據,事實上,它只比較buffer中剩余的元素是否一樣。
compareTo()
compareTo()方法比較兩個buffer的剩余元素(字節,字符等),用于例如: 排序。
在下列情況下,緩沖區被認為比另一個緩沖區“小”:
比較是針對每個緩沖區你剩余數據(從 position 到 limit)進行的,與它們在 equals() 中的方式相同,直到不相等的元素被發現或者到達緩沖區的上界。如果一個緩沖區在不相等元素發現前已經被耗盡,較短的緩沖區被認為是小于較長的緩沖區。
if (buffer1.compareTo(buffer2) < 0) { // do sth, it means buffer2 < buffer1,not buffer1 < buffer2 doSth(); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76360.html
摘要:而我們現在都已經發布了,的都不知道,這有點說不過去了。而對一個的讀寫也會有響應的描述符,稱為文件描述符,描述符就是一個數字,指向內核中的一個結構體文件路徑,數據區等一些屬性。 前言 只有光頭才能變強 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 本來我預想是先來回顧一下傳統的IO模式的,將傳統的IO模式的相關類理清楚(因為IO的類很多)。 但是,發現在整理的過程已...
摘要:操作系統是能夠獲取到事件操作完成的事件,基于回調函數機制和操作系統的操作控制實現事件檢測機制。 前面的文章NIO基礎知識介紹了Java NIO的一些基本的類及功能說明,Java NIO是用來替換java 傳統IO的,NIO的一些新的特性在網絡交互方面會更加的明顯。 Java 傳統IO的弊端 ????基于JVM來實現每個通道的輪詢檢查通道狀態的方法是可行的,但仍然是有問題的,檢查每個通道...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
摘要:后改良為用線程池的方式代替新增線程,被稱為偽異步。最大的問題是阻塞,同步。每次請求都由程序執行并返回,這是同步的缺陷。這些都會被注冊在多路復用器上。多路復用器提供選擇已經就緒狀態任務的能力。并沒有采用的多路復用器,而是使用異步通道的概念。 Netty是一個提供異步事件驅動的網絡應用框架,用以快速開發高性能、高可靠的網絡服務器和客戶端程序。Netty簡化了網絡程序的開發,是很多框架和公司...
閱讀 2723·2023-04-25 22:15
閱讀 1804·2021-11-19 09:40
閱讀 2149·2021-09-30 09:48
閱讀 3214·2021-09-03 10:36
閱讀 2026·2021-08-30 09:48
閱讀 1854·2021-08-24 10:00
閱讀 2725·2019-08-30 15:54
閱讀 699·2019-08-30 15:54