首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java I/O 流體系全景圖:從字節流到字符流,從阻塞到 NIO.2

     編輯:Java 程式設計入門

核心抽象:流的本質

流 是有序數據序列的傳輸通道,屏蔽了底層設備差異(文件、網絡、內存、管道)。Java I/O 採用裝飾器模式,通過組合不同流類實現功能疊加。

四大抽象基類(字節/字符 × 輸入/輸出)

輸入流 (讀)輸出流 (寫)
字節流 (8-bit)InputStreamOutputStream
字符流 (16-bit Unicode)ReaderWriter

轉換橋樑:InputStreamReader (字節→字符)、OutputStreamWriter (字符→字節),核心參數是 Charset。

節點流 vs 處理流(裝飾器)

  • 節點流:直接操作數據源/目的地。
    FileInputStream, FileReader, ByteArrayInputStream, PipedInputStream
  • 處理流:包裝節點流或其他處理流,提供增強功能。
    BufferedInputStream, DataInputStream, ObjectInputStream, BufferedReader, PrintWriter

設計模式體現:`FilterInputStream` 為裝飾器基類,構造函數接收 `InputStream`,所有 `read()` 委托給被包裝流,子類覆寫增加邏輯(如緩衝、數據類型轉換)。

常用流組合速查表

場景推薦組合關鍵點
高效讀寫文本文件BufferedReader / BufferedWriter行讀取 `readLine()`,默認 8KB 緩衝
高效讀寫二進制文件BufferedInputStream / BufferedOutputStream字節緩衝,減少系統調用
基本類型/字符串序列化DataInputStream / DataOutputStream按數據類型讀寫,跨平台一致
對象序列化ObjectInputStream / ObjectOutputStream實現 Serializable,注意 serialVersionUID
格式化輸出控制台/文件PrintStream / PrintWriterprintln/printf,不拋 IOException
內存數據交換ByteArrayInputStream / ByteArrayOutputStream內存緩衝區,toByteArray() 獲取數據
進程/線程間通信PipedInputStream / PipedOutputStream配對使用,連接管道
隨機訪問文件RandomAccessFileseek() 定位,read/write 同一對象,實現 DataInput/Output

字符編碼:避坑指南


// ❌ 錯誤:依賴平台默認編碼,跨平台亂碼
new FileReader("file.txt");
new FileWriter("file.txt");

// ✅ 正確:顯式指定 UTF-8
new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8);
new OutputStreamWriter(new FileOutputStream("file.txt"), StandardCharsets.UTF_8);

// Java 11+ 更簡潔
Files.newBufferedReader(path, StandardCharsets.UTF_8);
Files.newBufferedWriter(path, StandardCharsets.UTF_8);

獲取系統默認編碼:`Charset.defaultCharset()` 或 `System.getProperty("file.encoding")`。

NIO (New I/O) 與 NIO.2 現代化升級

NIO 核心三大組件 (JDK 1.4)

  • Channel (通道):雙向、可非阻塞。`FileChannel`, `SocketChannel`, `ServerSocketChannel`, `DatagramChannel`
  • Buffer (緩衝區):固定大小容器。`ByteBuffer`, `CharBuffer`, `IntBuffer`... 核心屬性:capacity, position, limit。操作:`flip()`, `clear()`, `compact()`, `rewind()`
  • Selector (選擇器):多路復用器,單線程管理多 Channel,事件驅動 (OP_READ, OP_WRITE, OP_CONNECT, OP_ACCEPT)

NIO.2 文件系統 API (JDK 7+) —— 實際開發主力


// Path 操作
Path path = Paths.get("/data", "logs", "app.log");
Path abs = path.toAbsolutePath();
Path rel = base.relativize(path);
Path resolved = path.resolveSibling("backup.log");

// 文件屬性
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
attrs.creationTime(); attrs.size(); attrs.isDirectory();

// 遍歷目錄樹 (流式、可並行)
Files.walk(root, 3) // 最大深度
    .filter(p -> p.toString().endsWith(".log"))
    .forEach(System.out::println);

// 複製/移動/刪除 (原子性選項)
Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
Files.move(src, dest, StandardCopyOption.ATOMIC_MOVE);
Files.deleteIfExists(path);

// 讀寫小文件 (一行代碼)
List lines = Files.readAllLines(path, StandardCharsets.UTF_8);
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE);

// 大文件流式處理
try (Stream lines = Files.lines(path)) {
    lines.filter(s -> s.contains("ERROR")).forEach(System.out::println);
}

RandomAccessFile:特殊的隨機訪問者

不屬於流體系,直接繼承 `Object`,實現 `DataInput`/`DataOutput`。模式:"r" (只讀)、"rw" (讀寫)、"rws" (同步元數據)、"rwd" (同步數據)。
核心方法:seek(long pos) 移動文件指針,getFilePointer() 獲取當前位置,setLength(long len) 截斷/擴展文件。
現代替代:`FileChannel` + `MappedByteBuffer` (內存映射文件) 性能更優。

最佳實踐總結

  1. 文本處理首選:`Files.newBufferedReader/Writer` (JDK 11+) 或 `BufferedReader/Writer` + 顯式 UTF-8。
  2. 二進制高效複製:`FileChannel.transferTo/From` (零拷貝) 或 `BufferedInputStream/OutputStream` 8KB+ 緩衝。
  3. 資源管理:強制使用 try-with-resources,避免泄漏。
  4. 序列化慎用:首選 JSON/Protobuf/Avro;必須用 Java 序列化時,鎖定 `serialVersionUID`,防範反序列化漏洞。
  5. 大文件處理:流式 API (`Files.lines`, `Files.walk`)、內存映射 (`FileChannel.map`)、分片並行。
  6. 網絡 I/O:高併發選 Netty (基於 NIO),簡單場景 `SocketChannel` + `Selector`。

總結

Java I/O 經歷了三代演進:BIO (流裝飾器) → NIO (Channel/Buffer/Selector) → NIO.2 (Path/Files/Async)。理解字節/字符轉換、裝飾器組合、緩衝機制、編碼指定、NIO.2 文件 API 是寫出健壯、高效 I/O 代碼的關鍵。現代項目以 NIO.2 為主,Netty 處理網絡,避免直接操作 Selector 和舊式流組合。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved