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)文章
springmvc請求轉(zhuǎn)發(fā)和重定向問題(攜帶參數(shù)和不攜帶參數(shù))
這篇文章主要介紹了springmvc請求轉(zhuǎn)發(fā)和重定向問題(攜帶參數(shù)和不攜帶參數(shù)),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
詳解Spring Boot整合Mybatis實現(xiàn) Druid多數(shù)據(jù)源配置
本篇文章主要介紹了詳解Spring Boot整合Mybatis實現(xiàn) Druid多數(shù)據(jù)源配置,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-03-03

