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

計算機程序思維邏輯 (58):字符流與字節流的本質區別、編碼陷阱與 Java IO 體系全景

     編輯:Java 綜合教學

計算機程序思維邏輯 (58):字符流與字節流的本質區別、編碼陷阱與 Java IO 體系全景

系列第 58 篇,深入剖析 Java IO 中最核心、最易混淆的字節流與字符流體系,從二進制視角重構理解,徹底搞懂編碼、轉換、緩衝、裝飾模式。

核心認知重構:一切皆位元組

文件在磁碟上只有位元組 (bytes),沒有字符 (chars)。 字符是內存中概念,位元組是存儲/傳輸概念。二者橋樑是 **編碼**。

直觀實驗:整數 123 的兩種存儲形態

二進制存儲 (DataOutputStream):

DataOutputStream out = new DataOutputStream(new FileOutputStream("test.dat"));
out.writeInt(123); // 寫入 4 字節: 00 00 00 7B (大端序)

UltraEdit 十六進制視圖:00 00 00 7B → 最低位字節 7B = 123。

文本存儲 (字符流):

OutputStream out = new FileOutputStream("test.txt");
String data = Integer.toString(123); // "123"
out.write(data.getBytes("UTF-8"));   // 3 字節: 31 32 33

十六進制:31 32 33 → ASCII '1'=49(0x31), '2'=50(0x32), '3'=51(0x33)。

編碼決定位元組序列

同一文本 "hello, 123, 老馬" 不同編碼位元組長度不同:

編碼英文/數字中文總字節數十六進制片段
UTF-81 字節3 字節變長UTF-8
GB180301 字節2 字節變長GB18030
UTF-16BE2 字節2 字節定長UTF-16BE

Java 內存中 char 固定 2 字節 (UTF-16BE),這是字符流操作的基礎單位。

字節流 vs 字符流 體系對照

維度字節流 (Byte Stream)字符流 (Char Stream)
基類InputStream / OutputStreamReader / Writer (抽象類)
處理單位byte (8 bits)char (16 bits, UTF-16)
編碼感知無有 (構造時指定或平台默認)
適用場景圖片、視頻、二進制文件、網絡傳輸文本文件、配置文件、源代碼、日誌
按行讀取不支援BufferedReader.readLine() 支援

Java 字符流核心類全景

1. 基礎抽象

  • Reader / Writer:所有字符流父類,定義 read()/write() 等核心協議

2. 轉換橋樑 (關鍵!)

  • InputStreamReader:位元組流 → 字符流,**解碼** (指定 Charset)
  • OutputStreamWriter:字符流 → 位元組流,**編碼** (指定 Charset)
  • 凡是字符流操作文件/網絡,底層必經此兩類轉換

3. 文件專用

  • FileReader / FileWriter:隱式使用平台默認編碼,**生產禁用**,跨平台亂碼根源
  • 替代:new FileReader(file, StandardCharsets.UTF_8) (Java 11+) 或 手動鏈 new InputStreamReader(new FileInputStream(file), "UTF-8")

4. 內存數組/字符串源

  • CharArrayReader/Writer:char[] 為源/目標
  • StringReader/Writer:String/StringBuilder 為源/目標
  • 單元測試、字符串處理常用

5. 裝飾器模式精華:緩衝與按行

  • BufferedReader / BufferedWriter:緩衝區 + readLine()/newLine(),大幅提升 IO 效能,支援按行處理
  • PrintWriter:包裝 Writer,提供 print/println/printf 格式化輸出,**自動 flush 可選**

6. 特殊角色:Scanner

  • 非 Reader 子類,但功能類似:按分隔符解析基本類型 (nextInt(), nextDouble() 等)
  • 掃描器模式,適合簡單文本解析,非高性能場景

標準流與錯誤流

System.in   // InputStream (標準輸入,鍵盤)
System.out  // PrintStream (標準輸出,螢幕) - 字節流但可直接打印字符
System.err  // PrintStream (標準錯誤,螢幕) - 同 out,獨立重定向

// 字符流包裝標準輸入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();

實用工具方法總結

  1. 讀取文本文件全部內容 (Java 11+): Files.readString(path, StandardCharsets.UTF_8)
  2. 寫入文本文件: Files.writeString(path, content, StandardCharsets.UTF_8)
  3. 按行處理大文件 (流式,低內存):
    try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
        lines.forEach(line -> process(line));
    }
  4. 複製流 (通用工具): IOUtils.copy(input, output) (Commons IO) 或 input.transferTo(output) (Java 9+)

避坑檢查清單

  • [ ] 所有文本文件操作**顯式指定 UTF-8** (或業務約定編碼)
  • [ ] 禁用 FileReader/FileWriter、new String(bytes) 無參構造
  • [ ] 字節流轉字符流**必須**經 InputStreamReader/OutputStreamWriter
  • [ ] 大文件**必須**用緩衝流 + 流式處理,禁用 readAllBytes
  • [ ] try-with-resources 確保資源關閉 (Java 7+)
  • [ ] 網絡協議層用字節流,應用層解析用字符流,分層清晰

下一篇將探討:NIO.2 (Path/Files/AsynchronousFileChannel)、零拷貝、內存映射文件、Netty ByteBuf 與標準 IO 的轉換。

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