java nio教程_Java NIO教程
java nio教程
1.簡介
Java NIO是Java 1.4引入的一個庫。 自從Java NIO推出以來,它提供了另一種方法來處理I / O和網絡事務。 它被認為是Java網絡和Java IO庫的替代方法。 開發Java NIO的目的是使輸入和輸出的事務異步和非阻塞。 阻塞和非阻塞IO的概念將在后面的部分中介紹。
目錄
1.簡介 2. IO中的術語2. Java NIO中的術語
Java NIO在使用Java的I / O處理中引入了許多新術語。 在較早的場景中,Java I / O基于字符流和字節流。 但是,使用Java NIO,現在可以通過通道讀取和處理數據-通過Channel進入緩沖區或通過緩沖區進入通道。 在本節中,我們將討論與Java NIO相關的各種術語,以幫助我們更好地理解進一步的教程。
2.1阻止輸入和輸出
使用字符流和字節流,文件被加載到JVM內存中并被鎖定以進行讀取或寫入。 這導致其他試圖讀取同一文件的程序處于阻塞狀態。 盡管有可用的處理能力,但由于程序被迫等待,因此這種情況浪費了CPU的能力。 讀取或寫入數據的這種安排稱為阻塞輸入和輸出。
2.2無阻塞輸入和輸出
隨著無阻塞輸入和輸出進入畫面,數據開始被讀取到通道中。 在無阻塞的輸入和輸出布置中,JVM使用通道來緩沖數據。 這些通道允許動態讀取數據,而不會阻止文件供外部使用。 通道是一塊緩沖的內存,一旦讀取了先前的緩沖數據,就將其填充。 這樣可以確保在完整的讀取周期中不會阻止該文件,并且其他程序也可以對該文件進行必要的訪問。
Java NIO主要涉及三個術語:
- 頻道
- 選擇器
- 緩沖液
這些術語將在本文中進一步聲明。
3. Java NIO –術語
如上所述,Java非阻塞IO在通道和緩沖區上工作。 在本節中,我們將嘗試理解這些術語以及其他術語選擇器。 這些術語對于遵循后續教程很重要。
3.1緩沖區
緩沖區是固定的一塊內存,用于在將數據讀入通道之前存儲該數據。 緩沖區可確保預定義大小的數據,以加快文件,輸入和數據流的讀取速度。 緩沖區的大小可配置為2到冪n的塊。
根據輸入類型,可以使用各種類型的緩沖區:
- ByteBuffer:用于按字節讀取字符流或文件
- CharBuffer:用于讀取完整ASCII集內的字符
- DoubleBuffer:專門用于雙重數據值,例如來自傳感器的讀數
- FloatBuffer:用于讀取恒定數據流,用于分析之類的目的
- LongBuffer:用于讀取長數據類型的值
- IntBuffer:用于讀取分數或結果的整數值
- ShortBuffer:用于讀取短整數值
每個緩沖區都有其特定用途。 通常用于文件的緩沖區是ByteBuffer和CharBuffer。 創建字節緩沖區的簡短示例如下所示。
RandomAccessFile aFile = new RandomAccessFile("src/data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); ByteBuffer buf = ByteBuffer.allocate(48);在上面的代碼中,正在創建48個字節的緩沖區。 必須指定緩沖區大小。 第三行將48字節的存儲空間分配給緩沖區buf。 這樣可以確保將必要的內存預先分配給緩沖區。 在繼續使用它們進行通道讀寫之前,有必要了解緩沖區的讀寫過程。 下圖顯示了從文件讀取字節的典型緩沖區。
緩沖區讀取
可以看出,緩沖區讀取并向左推送第一個字節。 緩沖區是后進先出類型的內存分配。 因此,當您希望使用緩沖區讀取文件時,必須先翻轉它才能讀取文件。 沒有翻轉,數據將以相反的順序輸出。 為了翻轉緩沖區,需要執行以下簡單代碼行:
buf.flip();buffer.flip()
一旦將數據讀入緩沖區,就該實際獲取已讀取的數據了。 為了讀取數據,使用了buf.get()函數。 此函數調用在每次調用時都讀取一個字節/字符/數據包,具體取決于緩沖區的類型。 讀取可用數據后,還需要在下一次讀取之前清理緩沖區。 必須進行清理以確保釋放空間以讀取更多數據。 為了清洗緩沖區,有兩種可行的方法-清除緩沖區或壓縮緩沖區。
要清除緩沖區,請執行命令buf.clear() 。 要壓縮緩沖區,請使用命令buf.compact() 。 這兩個命令最終都會做同樣的事情。 但是, compact()僅清除使用函數buf.get()讀取的數據。 因此,當我們需要繼續優化緩沖區使用的內存量時使用它。
3.1.1緩沖區屬性
緩沖區本質上具有3個屬性:
在緩沖區寫入期間,緩沖區位置是當前字節正在寫入的位置。 在緩沖區讀取過程中,緩沖區位置是從中讀取字節的位置。 隨著我們進行讀取或寫入操作,緩沖區位置不斷動態變化。
在緩沖區寫入過程中,緩沖區限制是可以寫入緩沖區的最大數據大小。 本質上,緩沖區限制和緩沖區容量在緩沖區寫入期間是同義詞。 但是,在緩沖區讀取期間,緩沖區限制是可從緩沖區讀取的可用字節數。 因此,當彈出字節時,緩沖區限制將繼續減小。
緩沖區容量是可以在任何時間點寫入緩沖區或從緩沖區讀取的最大數據。 因此,上面分配的大小48也稱為緩沖區容量。
3.1.2讀取和寫入緩沖區
緩沖區本質上是一種存儲數據的介質,直到線程從緩沖區中讀取數據并請求新數據為止。 從輸入源讀取數據的主要步驟是將數據讀取到緩沖區中。 為了將數據讀入緩沖區,使用了如下所示的代碼片段。
FileChannel inChannel = aFile.getChannel(); System.out.println("Created file Channel.."); ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); 在上面的代碼中,我們創建一個FileChannel來從文件中讀取數據,并創建一個緩沖區buf來保存數據。 然后使用語句inChannel.read(buf)將緩沖區用于讀取通道的數據。 執行此語句后,緩沖區現在將保留多達48個字節的可用數據。
為了開始讀取數據,您使用了一個簡單的語句buf.get() 。
3.1.3標記并重置緩沖區
在讀取過程中,通常需要重復從特定位置讀取數據。 在正常情況下,一旦您從緩沖區中獲取數據,就認為該數據已消失。 但是,可以在特定的索引處標記緩沖區,從而可以再次從特定位置讀取緩沖區。 下面的代碼演示了如何完成此操作。
buffer.mark();char x = buffer.get(); char y = buffer.get(); char z = buffer.get(); char a = buffer.get(); //Do something with above databuffer.reset(); //set position back to mark.標記和重置的主要應用是重復分析數據,重復重復信息,發送命令特定次數甚至更多。
3.2頻道
通道是非阻塞IO的主要介質。 通道類似于可用于阻止IO的流。 這些通道支持網絡數據以及文件數據IO。 當需要時,通道從緩沖區讀取數據。 緩沖區將保存數據,直到從緩沖區讀取數據為止。
通道具有多種實現方式,具體取決于要讀取的數據。 以下列出了可用于渠道的標準實現:
- FileChannel:用于從文件讀取數據和向文件寫入數據
- DatagramChannel:用于使用UDP數據包通過網絡進行數據交換
- SocketChannel:用于通過TCP套接字交換數據的TCP通道
- ServerSocketChannel:類似于Web服務器的實現,它通過特定的TCP端口偵聽請求。 它為每個新連接創建一個新的SocketChannel實例
從通道名稱可以理解,除了文件IO之外,它們還涵蓋UDP + TCP網絡IO流量。 與可以在特定時刻讀取或寫入的Streams不同,同一Channel可以無縫讀取和寫入資源。 通道支持異步讀寫,這確保了在不妨礙代碼執行的情況下讀取數據。 上面討論的緩沖區支持通道的這種異步操作。
3.2.1通道分散和聚集
Java NIO固有地支持數據分散和收集,以便從多個緩沖區讀取數據或將數據寫入多個緩沖區。 Java NIO足夠智能,可以管理多個緩沖區中的讀取和寫入。
Java NIO分散用于將通道中的讀取分散到多個緩沖區中。 它的代碼實現非常簡單。 您需要做的就是添加一個緩沖區數組作為讀取的參數。 下面顯示了相同的代碼段。
在上面的代碼中,我們創建了兩個每個128字節的緩沖區。 注意這里我們創建了一個包含兩個緩沖區的數組。 該數組作為參數進一步傳遞給讀取的通道。 通道將數據讀入第一個緩沖區,直到達到緩沖區容量。 達到緩沖區容量后,通道將自動切換到下一個緩沖區。 因此,讀取的通道被分散而對線程沒有任何影響。
Java NIO收集也以類似的方式工作。 讀取到多個緩沖區的數據也可以收集并寫入單個通道。 下面的代碼片段做了類似的事情。
該代碼類似于分散讀取。 需要理解的是信息的寫入順序。 信息從第一個緩沖區開始寫入通道。 達到第一個緩沖區的限制后,通道會自動切換到下一個緩沖區。 重要的是要注意在此寫入過程中不會發生翻轉。 如果需要在寫入之前翻轉緩沖區,則需要在將緩沖區分配給數組之前完成。
3.2.2頻道轉移
顧名思義,通道傳輸是將數據從一個通道傳輸到另一個通道的過程。 可以從通道緩沖區的特定位置進行通道傳輸。 但是,在位置值設置為零的情況下,可以將完整的輸入源復制或復制到指定的輸出目標。 例如,在關鍵字和文本編輯器之間建立通道,將使您能夠將輸入從鍵盤連續傳輸到文本編輯器。
為了促進通道傳輸,Java NIO配備了兩個函數,即transferFrom()和transferTo() 。 這些功能的用途從它們的標識符中很清楚。 讓我們以一個例子來更好地理解這些功能。
我們將使用上面創建的data.txt文件作為輸入源。 我們會將數據從該文件傳輸到新文件output.txt 。 下面的代碼使用transferFrom()方法調用執行相同的操作。
ChannelTransfer.java
import java.io.RandomAccessFile; import java.nio.channels.FileChannel;public class ChannelTransfer {public static void main(String[] args) {try {RandomAccessFile copyFrom = new RandomAccessFile("src/data.txt", "rw");FileChannel fromChannel = copyFrom.getChannel();RandomAccessFile copyTo = new RandomAccessFile("src/output.txt", "rw");FileChannel toChannel = copyTo.getChannel();long count = fromChannel.size();toChannel.transferFrom(fromChannel, 0, count);} catch (Exception e) {System.out.println("Error: " + e);}} }從上面的代碼中可以看出,通道fromChannel用于從data.txt中讀取數據。 toChannel用于從位置0開始的fromChannel獲取數據。重要的是要注意,整個文件都是使用FileChannel復制的。 但是,在SocketChannel某些實現中,情況可能并非如此。 在這種情況下,僅復制在傳輸時可在緩沖區中讀取的數據。 此行為是由于SocketChannel實現的動態性質引起的。
transferTo的實現非常相似。 唯一需要做的更改是方法調用將使用源對象完成,而目標通道對象將是方法調用中的一個參數。
3.3選擇器
顧名思義,選擇器用于從多個通道中選擇一個通道。 當您計劃使用單個線程并行管理多個資源時,Java NIO中的選擇器特別有用。 選擇器充當線程和開放通道之間的橋梁。 選擇器通常在預期線程流量較低但需要使用多個資源的情況下使用。 選擇器可能扮演的角色的示意圖設計如下所示。
NIO選擇器
選擇器的創建非常簡單。 下面的代碼段說明了如何創建選擇器以及如何在選擇器中注冊頻道。
Selector myFirstSelector = Selector.open(); //opens the selector SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); SelectionKey selectorKey = channel.register(myFirstSelector, SelectionKey.OP_READ); 上面的代碼創建一個SocketChannel ,將其配置為非阻塞并將其注冊到選擇器。 請注意,我們使用了SocketChannel 。 選擇器需要可配置為非阻塞的通道。 因此,選擇器不能與FileChannel一起使用。
需要注意的另一點是注冊SocketChannel的第二個參數。 該參數指定我們要監視的通道事件。 選擇器等待事件,并在事件觸發時更改其狀態。 這些事件在下面列出:
可以使用如下所示的靜態常量來配置這些事件:
選擇器為我們提供了預定義的功能,以檢查這些事件的發生。 以下方法調用是不言自明的,可用于監視這些事件的發生。
key.isAcceptable(); key.isConnectable(); key.isReadable(); key.isWritable();因此,當我們計劃用較少的線程管理多個資源時,選擇器非常有用。
4. NIO頻道
4.1文件通道
這種類型的通道通常用于讀取和寫入文件。 下面顯示了用于創建通道并將其用于讀寫的示例代碼
ChannelRW.java
import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel;public class ChannelRW {public static void main(String[] args) {System.out.println("Starting the file read..");try {RandomAccessFile aFile = new RandomAccessFile("src/data.txt", "rw");FileChannel inChannel = aFile.getChannel();System.out.println("Created file Channel..");ByteBuffer buf = ByteBuffer.allocate(48);int bytesRead = inChannel.read(buf);while (bytesRead != -1) {System.out.println("\nRead " + bytesRead);buf.flip();while(buf.hasRemaining()){System.out.print((char) buf.get());}buf.clear();bytesRead = inChannel.read(buf);}aFile.close();}catch(Exception e) {System.out.println("Error:"+e);}} }data.txt
Hello, This is my first NIO read. I am reading multiple lines. The code is implemented for Javacodegeeks by Abhishek Kothari在上面的代碼中,我們試圖讀取如上所述創建的data.txt文件。 正在使用Java NIO庫讀取該文件。 文件讀取過程涉及多個步驟。 下面顯示了針對它的逐步代碼說明。
上面代碼的輸出如下所示:
Starting the file read.. Created file Channel..Read 48 Hello, This is my first NIO read. I am reading m Read 48 ultiple lines. The code is implemented for Javac Read 28 odegeeks by Abhishek Kothari可見,數據以48個字節的塊讀取,并且每次出現“ Read 48 ”語句以顯示已讀取的字節數。 可以看出,當到達文件末尾時,只能讀取28個字節,因此返回計數28。
4.2 SocketChannel
這種類型的通道用于連接到http套接字。 連接到套接字的簡單代碼如下所示:
SocketChannel sc = SocketChannel.open(); sc.connect(new InetSocketAddress("https://javacodegeeks.com", 8080));套接字通道在執行方法調用時連接到指定的URL。 為了關閉開放通道,只需執行如下所示的相應方法調用即可。
sc.close();從SocketChannel讀取數據的過程類似于FileChannel 。
4.3 ServerSocketChannel
服務器套接字通道用于讀取來自套接字客戶端的套接字數據。 可以使用以下代碼段將該通道配置為讀取。
ServerSocketChannel ssc = ServerSocketChannel.open();ssc.socket().bind(new InetSocketAddress(8080));while(true){SocketChannel sc =ssc.accept();//do something with sc... }上面的代碼打開服務器端套接字,并允許來自外部SocketChannel客戶端的套接字連接。 從上面的代碼可以理解, ServerSocketChannel僅需要端口號即可啟動套接字服務器。 一旦啟動,它可以創建自己的SocketChannel來接受來自其他套接字的數據。 這就是使用Java NIO進行無阻塞Socket IO連接的方式。
5.結論
本文詳細討論了Java NIO的各種術語。 它說明了使用各種NIO通道以非阻塞方式讀取和寫入數據的過程。 關于Java NIO庫,例如DatagramChannel,Pipes,Async通道等,還有更多的要探索。
翻譯自: https://www.javacodegeeks.com/2018/07/java-nio-tutorial.html
java nio教程
總結
以上是生活随笔為你收集整理的java nio教程_Java NIO教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Redmi K70系列细节曝光:最早11
- 下一篇: 鲜花电商花加发布全员信:进入停业整顿阶段