Java IO和NIO的基本概念和API詳解
一、 Java IO (Blocking IO)
基本概念
- Java IO 是 Java 平臺提供的用于進行輸入和輸出操作的 API。
- Java IO 基于 流 (Stream) 的模型,數(shù)據(jù)像水流一樣從一個地方流向另一個地方。
- Java IO 主要是 阻塞式 I/O (Blocking I/O),即線程在執(zhí)行 I/O 操作時會被阻塞,直到操作完成。
- 傳統(tǒng)IO指的是
java.io
包下的部分組件(File, InputStream, OutputStream, Reader, Writer)。
IO 流的分類
按數(shù)據(jù)傳輸方向:
- 輸入流 (Input Stream): 用于從數(shù)據(jù)源讀取數(shù)據(jù)(例如,從文件、網(wǎng)絡(luò)連接、鍵盤等)。 以
InputStream
或Reader
作為基類。 - 輸出流 (Output Stream): 用于將數(shù)據(jù)寫入到目標(例如,寫入到文件、網(wǎng)絡(luò)連接、控制臺等)。 以
OutputStream
或Writer
作為基類。
按數(shù)據(jù)傳輸單位:
- 字節(jié)流 (Byte Stream): 以字節(jié) (8 bits) 為單位進行數(shù)據(jù)傳輸。 以
InputStream
和OutputStream
作為基類。 適用于處理二進制數(shù)據(jù)(例如,圖片、音頻、視頻等)。 - 字符流 (Character Stream): 以字符 (16 bits) 為單位進行數(shù)據(jù)傳輸。 以
Reader
和Writer
作為基類。 適用于處理文本數(shù)據(jù)。
核心類和接口
InputStream
(字節(jié)輸入流):
FileInputStream
: 從文件中讀取字節(jié)。ByteArrayInputStream
: 從字節(jié)數(shù)組中讀取字節(jié)。ObjectInputStream
: 從對象流中讀取對象。BufferedInputStream
: 帶緩沖的字節(jié)輸入流,提高讀取效率。
OutputStream
(字節(jié)輸出流):
FileOutputStream
: 向文件中寫入字節(jié)。ByteArrayOutputStream
: 向字節(jié)數(shù)組中寫入字節(jié)。ObjectOutputStream
: 向?qū)ο罅髦袑懭雽ο蟆?/li>BufferedOutputStream
: 帶緩沖的字節(jié)輸出流,提高寫入效率。
Reader
(字符輸入流):
FileReader
: 從文件中讀取字符。CharArrayReader
: 從字符數(shù)組中讀取字符。BufferedReader
: 帶緩沖的字符輸入流,提高讀取效率。InputStreamReader
: 將字節(jié)輸入流轉(zhuǎn)換為字符輸入流(需要指定字符編碼)。
Writer
(字符輸出流):
FileWriter
: 向文件中寫入字符。CharArrayWriter
: 向字符數(shù)組中寫入字符。BufferedWriter
: 帶緩沖的字符輸出流,提高寫入效率。OutputStreamWriter
: 將字節(jié)輸出流轉(zhuǎn)換為字符輸出流(需要指定字符編碼)。File
: 表示文件或目錄的抽象表示。
IO 操作流程 (以讀取文件為例)
- 創(chuàng)建
File
對象: 指定要讀取的文件路徑。 - 創(chuàng)建
FileInputStream
對象: 將File
對象作為參數(shù)傳遞給FileInputStream
的構(gòu)造方法,創(chuàng)建一個FileInputStream
對象。 - 創(chuàng)建
BufferedInputStream
對象 (可選): 將FileInputStream
對象作為參數(shù)傳遞給BufferedInputStream
的構(gòu)造方法,創(chuàng)建一個BufferedInputStream
對象,提高讀取效率。 - 讀取數(shù)據(jù): 使用
read()
方法從輸入流中讀取數(shù)據(jù)。 - 關(guān)閉流: 在完成讀取操作后,務(wù)必關(guān)閉輸入流,釋放資源(先關(guān)閉
BufferedInputStream
,再關(guān)閉FileInputStream
)。
代碼示例 (讀取文件內(nèi)容):
import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class IOExample { public static void main(String[] args) { File file = new File("test.txt"); // 替換為你的文件路徑 try (FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis)) { // 使用 try-with-resources 語句,自動關(guān)閉流 byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = bis.read(buffer)) != -1) { // 處理讀取到的數(shù)據(jù) String data = new String(buffer, 0, bytesRead); System.out.print(data); } } catch (IOException e) { e.printStackTrace(); } } }
二、 Java NIO (Non-blocking IO)
基本概念
- Java NIO 是 Java 1.4 引入的一組新的 I/O API,旨在提供高性能、非阻塞的 I/O 操作。
- NIO 使用 通道 (Channel) 和 緩沖區(qū) (Buffer) 的模型,而不是流。
- NIO 主要是 非阻塞式 I/O (Non-blocking I/O),即線程在執(zhí)行 I/O 操作時不會被阻塞,而是可以執(zhí)行其他任務(wù)。
- NIO 使用 選擇器 (Selector) 來監(jiān)聽多個通道的事件,實現(xiàn)單線程管理多個連接。
核心組件
通道 (Channel):
- 通道類似于流,但可以進行雙向數(shù)據(jù)傳輸(既可以讀取數(shù)據(jù),也可以寫入數(shù)據(jù))。
- 常見的通道:
FileChannel
: 用于文件 I/O。SocketChannel
: 用于 TCP 網(wǎng)絡(luò) I/O (客戶端)。ServerSocketChannel
: 用于 TCP 網(wǎng)絡(luò) I/O (服務(wù)器端)。DatagramChannel
: 用于 UDP 網(wǎng)絡(luò) I/O。
緩沖區(qū) (Buffer):
- 緩沖區(qū)是用于存儲數(shù)據(jù)的容器,本質(zhì)上是一個字節(jié)數(shù)組 (ByteBuffer) 或字符數(shù)組 (CharBuffer)。
- NIO 使用緩沖區(qū)進行數(shù)據(jù)傳輸,而不是直接從通道讀取數(shù)據(jù)或向通道寫入數(shù)據(jù)。
- 常見的緩沖區(qū):
ByteBuffer
: 字節(jié)緩沖區(qū)。CharBuffer
: 字符緩沖區(qū)。ShortBuffer
: 短整型緩沖區(qū)。IntBuffer
: 整型緩沖區(qū)。LongBuffer
: 長整型緩沖區(qū)。FloatBuffer
: 浮點型緩沖區(qū)。DoubleBuffer
: 雙精度浮點型緩沖區(qū)。
選擇器 (Selector):
- 選擇器允許單個線程監(jiān)聽多個通道的事件(例如連接建立、數(shù)據(jù)可讀、數(shù)據(jù)可寫等)。
- 使用選擇器可以避免為每個連接創(chuàng)建一個線程,從而提高并發(fā)性能。
NIO 操作流程 (以讀取 SocketChannel 數(shù)據(jù)為例)
- 創(chuàng)建
ServerSocketChannel
: 監(jiān)聽客戶端連接。 - 創(chuàng)建
SocketChannel
: 接受客戶端連接。 - 將
SocketChannel
注冊到Selector
: 指定要監(jiān)聽的事件(例如OP_READ
,OP_WRITE
,OP_CONNECT
,OP_ACCEPT
)。 - 創(chuàng)建
ByteBuffer
: 用于存儲讀取到的數(shù)據(jù)。 - 調(diào)用
selector.select()
方法: 阻塞等待有事件發(fā)生的通道。 - 獲取就緒的通道:
selector.selectedKeys()
返回所有就緒通道的集合。 - 處理事件: 遍歷就緒通道的集合,根據(jù)不同的事件類型執(zhí)行相應(yīng)的操作(例如讀取數(shù)據(jù)、寫入數(shù)據(jù))。
- 讀取數(shù)據(jù): 調(diào)用
channel.read(buffer)
從通道讀取數(shù)據(jù)到緩沖區(qū)。 - 處理緩沖區(qū)數(shù)據(jù): 從緩沖區(qū)讀取數(shù)據(jù)并進行處理。
- 關(guān)閉通道和選擇器: 在完成操作后,務(wù)必關(guān)閉通道和選擇器,釋放資源。
代碼示例 (使用 SocketChannel 讀取數(shù)據(jù)):
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class NIOExample { public static void main(String[] args) throws IOException { // 1. 創(chuàng)建 SocketChannel SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("www.example.com", 80)); socketChannel.configureBlocking(false); // 設(shè)置為非阻塞模式 // 2. 創(chuàng)建 ByteBuffer ByteBuffer buffer = ByteBuffer.allocate(1024); // 3. 從 Channel 讀取數(shù)據(jù)到 Buffer int bytesRead = socketChannel.read(buffer); while (bytesRead > 0) { // 切換到讀模式 buffer.flip(); // 4. 從 Buffer 讀取數(shù)據(jù) while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } // 清空 Buffer,準備下一次讀取 buffer.clear(); bytesRead = socketChannel.read(buffer); } socketChannel.close(); } }
三、 Java IO 與 NIO 的區(qū)別
特性 | Java IO (Blocking IO) | Java NIO (Non-blocking IO) |
---|---|---|
數(shù)據(jù)傳輸方式 | 基于流 (Stream) | 基于通道 (Channel) 和緩沖區(qū) (Buffer) |
I/O 模型 | 阻塞式 I/O (Blocking I/O) | 非阻塞式 I/O (Non-blocking I/O) |
選擇器 | 沒有 | 有 (Selector) |
API | 簡單易用 | 相對復(fù)雜,需要理解通道、緩沖區(qū)、選擇器等概念 |
性能 | 性能較低 (高并發(fā)下) | 性能較高 (高并發(fā)下) |
線程模型 | 通常使用多線程模型 (每個連接一個線程) | 通常使用單線程多路復(fù)用模型 (一個線程管理多個連接) |
適用場景 | 低并發(fā)、連接數(shù)較少的應(yīng)用,或者可以接受阻塞的場景 | 高并發(fā)、連接數(shù)較多的應(yīng)用,需要高性能和非阻塞的場景,例如網(wǎng)絡(luò)服務(wù)器、聊天服務(wù)器等 |
四、 選擇哪種 I/O 模式?
- 如果你的應(yīng)用是低并發(fā)、連接數(shù)較少,并且可以接受阻塞,那么 Java IO 仍然是一個不錯的選擇,因為它簡單易用。
- 如果你的應(yīng)用是高并發(fā)、連接數(shù)較多,并且對性能要求很高,那么應(yīng)該使用 Java NIO。
- 一般情況建議直接使用NIO模型,性能更好。
總結(jié)
Java IO 和 NIO 都是 Java 平臺提供的用于進行輸入和輸出操作的 API。
Java IO 基于流的模型,使用簡單但性能較低; Java NIO 基于通道和緩沖區(qū)的模型,提供高性能、非阻塞的 I/O 操作。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
讀取Java文件到byte數(shù)組的三種方法(總結(jié))
下面小編就為大家?guī)硪黄x取Java文件到byte數(shù)組的三種方法(總結(jié))。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08Java中的信息摘要算法MessageDigest類用法詳解
這篇文章主要介紹了Java中的信息摘要算法MessageDigest類用法詳解,java.security.MessageDigest類為應(yīng)用程序提供信息摘要算法的功能,如MD5或SHA-1或SHA-256算法,信息摘要是安全的單向哈希函數(shù),它接收任意大小的數(shù)據(jù),并輸出固定長度的哈希值,需要的朋友可以參考下2024-01-01Spring-data-redis操作redis知識總結(jié)
這篇文章主要介紹了Spring-data-redis操作redis知識總結(jié),spring-data-redis是spring-data模塊的一部分,專門用來支持在spring管理項目對redis的操作。2017-04-04Java MultipartFile實現(xiàn)上傳文件/上傳圖片
這篇文章主要介紹了Java MultipartFile實現(xiàn)上傳文件/上傳圖片,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12