Java NIO和NIO.2有什麼區別? | baeldung
在本教程中,我們將介紹 Java IO 功能以及它們在不同 Java 版本中的變化。首先,我們將介紹初始 Java 版本中的java.io包。接下來,我們將回顧Java 1.4 中引入的java.nio包。最後,我們將介紹java.nio.file包,通常稱為 NIO.2 包。
Java NIO 包
第一個 Java 版本與java.io包一起釋出,引入了一個 File類來訪問檔案系統。File類表示檔案和目錄,並提供對檔案系統的有限操作。可以建立和刪除檔案,檢查它們是否存在,檢查讀/寫訪問等。
它也有一些缺點:
- 缺少複製方法——要複製一個檔案,我們需要建立兩個File例項並使用一個緩衝區來讀取一個並寫入另一個File例項。
- 錯誤處理錯誤 ——一些方法返回布林值作為操作成功與否的指示符。
- 一組有限的檔案屬性——名稱、路徑、讀/寫許可權、可用記憶體大小等等。
- 阻塞 API——我們的執行緒被阻塞,直到 IO 操作完成。
要讀取檔案,我們需要一個FileInputStream例項來從檔案中讀取位元組:
@Test public void readFromFileUsingFileIO() throws Exception { File file = new File("src/test/resources/nio-vs-nio2.txt"); FileInputStream in = new FileInputStream(file); StringBuilder content = new StringBuilder(); int data = in.read(); while (data != -1) { content.append((char) data); data = in.read(); } in.close(); assertThat(content.toString()).isEqualTo("Hello from file!"); } |
接下來,Java 1.4 引入了捆綁在java.nio包中的非阻塞 IO API (nio 代表新 IO)。引入 NIO 是為了克服java.io包的限制。這個包引入了三個核心類:Channel、Buffer和Selector:
- Channel
Java NIO Channel是一個允許我們讀取和寫入緩衝區的類。Channel類類似於Streams(這裡我們說的是 IO Streams,而不是 Java 1.8 Streams),但有一些不同之處。Channel是雙向的,而Streams通常是單向的,它們可以非同步讀寫。
Channel類有幾個實現,包括FileChannel用於檔案系統讀/寫,DatagramChannel 用於使用 UDP 在網路上讀/寫,以及SocketChannel用於使用 TCP 在網路上讀/寫。
- Buffer
Buffer緩衝區是一塊記憶體,我們可以從中讀取或寫入資料。NIO Buffer物件包裝了一個記憶體塊。Buffer類提供了一組與記憶體塊一起工作的功能。要使用Buffer物件,我們需要了解Buffer類的三個主要屬性:容量、位置和限制。
- 容量定義了記憶體塊的大小。當我們將資料寫入緩衝區時,我們只能寫入有限的長度。當緩衝區已滿時,我們需要讀取資料或清除資料。
- 位置是我們寫入資料的起點。一個空緩衝區從 0 開始到容量 - 1。另外,當我們讀取資料時,我們從位置值開始。
- 限制意味著我們如何從緩衝區寫入和讀取。
Buffer類有多種變體。每個原始 Java 型別一個,不包括Boolean型別和MappedByteBuffer。
要使用緩衝區,我們需要知道一些重要的方法:
- allocate(int value)——我們使用這個方法來建立一個特定大小的緩衝區。
- flip() - 此方法用於從寫入模式切換到讀取模式
- clear() –清除緩衝區內容的方法
- compact() –只清除我們已經閱讀的內容的方法
- rewind() -將位置重置為 0,以便我們可以重新讀取緩衝區中的資料
使用前面描述的概念,讓我們使用Channel和Buffer類從檔案中讀取內容:
@Test public void readFromFileUsingFileChannel() throws Exception { RandomAccessFile file = new RandomAccessFile("src/test/resources/nio-vs-nio2.txt", "r"); FileChannel channel = file.getChannel(); StringBuilder content = new StringBuilder(); ByteBuffer buffer = ByteBuffer.allocate(256); int bytesRead = channel.read(buffer); while (bytesRead != -1) { buffer.flip(); while (buffer.hasRemaining()) { content.append((char) buffer.get()); } buffer.clear(); bytesRead = channel.read(buffer); } file.close(); assertThat(content.toString()).isEqualTo("Hello from file!"); } |
在初始化所有需要的物件後,我們從通道讀取到緩衝區。接下來,在 while 迴圈中,我們使用flip()方法標記要讀取的緩衝區,並一次讀取一個位元組,並將其附加到我們的結果中。最後,我們清除資料並讀取另一批。
- Selector
Java NIO Selector允許我們用一個執行緒管理多個通道。要使用選擇器物件監控多個通道,每個通道例項必須處於非阻塞模式,並且我們必須註冊它。通道註冊後,我們得到一個SelectionKey物件,表示通道和選擇器之間的連線。當我們有多個通道連線到一個選擇器時,我們可以使用select()方法來檢查有多少通道可供使用。呼叫select()方法後,我們可以使用selectedKeys()方法獲取所有準備好的通道。
java.nio包引入的變化更多與底層資料 IO 相關。雖然他們允許非阻塞 API,但其他方面仍然存在問題:
- 對符號連結的有限支援
- 對檔案屬性訪問的有限支援
- 缺少更好的檔案系統管理工具
Java NIO.2 包
Java 1.7 引入了新的java.nio.file包,也稱為NIO.2 包。此包遵循java.nio包中不支援的非阻塞 IO 的非同步方法。最重要的變化與高階檔案操作有關。它們與Files、Path和Paths類一起新增。最顯著的低階更改是新增了AsynchroniousFileChannel和AsyncroniousSocketChannel。
- Path
Path物件表示由分隔符分隔的目錄和檔名的分層序列。根元件在最左邊,而檔案在右邊。此類提供實用方法,例如getFileName()、 getParent()等。 Path類還提供解析和相對化方法,幫助構建不同檔案之間的路徑。Paths 類是一組靜態實用程式方法,它們接收String或URI以建立Path例項。
- Files
Files類提供了使用前面描述的Path類並對檔案、目錄和符號連結進行操作的實用方法。它還提供了一種使用readAttributes()方法讀取許多檔案屬性的方法。
最後,讓我們看看 NIO.2 在讀取檔案時與之前的 IO 版本相比如何:
@Test public void readFromFileUsingNIO2() throws Exception { List<String> strings = Files.readAllLines(Paths.get("src/test/resources/nio-vs-nio2.txt")); assertThat(strings.get(0)).isEqualTo("Hello from file!"); } |
在本文中,我們介紹了java.nio和java.nio.file包的基礎知識。我們可以看到,NIO.2 並不是 NIO 包的新版本。NIO 包引入了用於非阻塞 IO 的低階 API,而 NIO.2 引入了更好的檔案管理。這兩個包不是同義詞,而是相互補充。與往常一樣,所有程式碼示例都可以在 GitHub 上找到。
相關文章
- 【Java面試】IO和NIO有什麼區別?Java面試
- Java和Python是什麼?有什麼區別?JavaPython
- Java 介面和抽象類是什麼,有什麼區別Java抽象
- 面試官:BIO、NIO、AIO是什麼,他們有什麼區別?面試AI
- java泛型中<?>和<T>有什麼區別?Java泛型
- *和body有什麼區別
- java和JavaScript究竟什麼關係,有什麼樣的區別JavaScript
- python和Java、C、ruby、PHP有什麼區別?PythonJavaPHP
- Java和HTML有什麼區別?哪個更重要?JavaHTML
- Java中long和Long有什麼區別 (轉載)Java
- java.util.Date和java.sql.Date有什麼區別?JavaSQL
- Cache 和 Buffer 有什麼區別?
- mongodb和mysql有什麼區別MongoDBMySql
- shim和polyfill有什麼區別
- float和double有什麼區別?
- int 和 Integer 有什麼區別
- cookie和session 有什麼區別?CookieSession
- session 和 cookie 有什麼區別?SessionCookie
- modbus和tcp有什麼區別?TCP
- Nginx和Apache有什麼區別?NginxApache
- COOKIE和SESSION有什麼區別?CookieSession
- RegisterClass和RegisterClassEx有什麼區別?
- for update 和 for update of 有什麼區別
- PEAR 和 PECL 有什麼區別?
- Activity和Fragment有什麼區別Fragment
- vue和react有什麼區別?VueReact
- Iterator和ListIterator有什麼區別
- Hifi和ONT 有什麼區別
- cookie是什麼?和session有什麼區別?CookieSession
- IPFS和區塊鏈有什麼區別區塊鏈
- Java NIO 和 IO 的區別詳解Java
- Java中使用新NIO.2讀寫檔案Java
- RPA和IPA有什麼區別
- Jsp和Servlet有什麼區別?JSServlet
- HTTP和HTTPS有什麼區別?HTTP
- VPS和HTTP有什麼區別?HTTP
- 命令和事件有什麼區別? - Oskar事件
- c++中&和&&有什麼區別C++