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

《Thinking in Java》經典 I/O 流範例深度解析:從檔案、記憶體到格式化輸出

     編輯:Java 相關知識

範例程式碼全景

本範例展示 Java I/O 體系的核心用法:BufferedReader、StringReader、DataInputStream、LineNumberReader、PrintWriter、DataOutputStream、隨機存取檔案等,串聯「讀取 -> 處理 -> 輸出」完整鏈路。

import java.io.*;

public class NewIODemo {
    public static void main(String[] args) {
        try {
            // 1. 按行讀取檔案 (args[0] 為檔案路徑)
            BufferedReader in = new BufferedReader(new FileReader(args[0]));
            String s, s2 = "";
            while ((s = in.readLine()) != null) s2 += s + "\n";
            in.close();

            // 1b. 讀取標準輸入
            BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("Enter a line:");
            System.out.println(stdin.readLine());

            // 2. 從記憶體字串讀取 (StringReader)
            StringReader in2 = new StringReader(s2);
            int c;
            while ((c = in2.read()) != -1) System.out.print((char)c);

            // 3. 格式化記憶體輸入 (DataInputStream + 已棄用 StringBufferInputStream)
            try {
                DataInputStream in3 = new DataInputStream(new StringBufferInputStream(s2));
                while (true) System.out.print((char)in3.readByte());
            } catch (EOFException e) {
                System.out.println("End of stream");
            }

            // 4. 行號輸出到檔案 (LineNumberReader + PrintWriter)
            try {
                LineNumberReader li = new LineNumberReader(new StringReader(s2));
                BufferedReader in4 = new BufferedReader(li);
                PrintWriter out1 = new PrintWriter(new BufferedWriter(new FileWriter("IODemo.out")));
                while ((s = in4.readLine()) != null) {
                    out1.println("Line " + li.getLineNumber() + s);
                }
                out1.close();
            } catch (EOFException e) {
                System.out.println("End of stream");
            }

            // 5. 基本資料類型儲存與讀取 (DataOutputStream / DataInputStream)
            try {
                DataOutputStream out2 = new DataOutputStream(
                    new BufferedOutputStream(new FileOutputStream("Data.txt")));
                out2.writeDouble(3.14159);
                out2.writeBytes("That was pi");
                out2.close();

                DataInputStream in5 = new DataInputStream(
                    new BufferedInputStream(new FileInputStream("Data.txt")));
                BufferedReader in5br = new BufferedReader(new InputStreamReader(in5));
                System.out.println(in5.readDouble()); // 讀回 double
                System.out.println(in5br.readLine()); // 讀回字串
            } catch (EOFException e) {
                System.out.println("End of stream");
            }

            // 6. 隨機存取檔案 (RandomAccessFile) 此處省略

        } catch (FileNotFoundException e) {
            System.out.println("File Not Found: " + args[0]);
        } catch (IOException e) {
            System.out.println("IO Exception");
        }
    }
}

核心設計模式:裝飾者模式

Java I/O 大量使用裝飾者模式動態組合功能:

  • FileReader (節點流) -> BufferedReader (緩衝) -> LineNumberReader (行號)
  • FileOutputStream -> BufferedOutputStream -> DataOutputStream (基本型別寫入)
  • 靈活組合,避免爆炸性子類膨脹。

關鍵技術點解析

場景關鍵類說明
高效行讀取BufferedReader.readLine()內部緩衝區減少系統調用,支援跨平台換行符
記憶體當檔案StringReader / StringWriter實現 CharSequence 與流介面互適配,單元測試常用
基本型別序列化DataInputStream / DataOutputStream機器無關二進制格式,適合資料檔而非文字檔
格式化文字輸出PrintWriter自動 flush、不拋 IOException、支援 printf 格式化
行號追蹤LineNumberReader裝飾 BufferedReader,getLineNumber() 獲取當前行號
標準輸入System.in -> InputStreamReader -> BufferedReader將位元組流轉字元流並緩衝

遺留與現代化對比

  • 已棄用:StringBufferInputStream、DataInputStream.readLine()(不正確處理字元集)。
  • 現代替代:
    • NIO.2 Files.readAllLines(Path)、Files.lines(Path) (Stream API)
    • StandardCharsets.UTF_8 明確指定編碼
    • try-with-resources 自動關閉資源 (Java 7+)
    • RandomAccessFile 仍為隨機存取首選,或 FileChannel + MappedByteBuffer (NIO)

學習建議

  1. 手動輸入代碼,觀察各流包裝順序與資料轉換方向。
  2. 嘗試用 try-with-resources 重構所有 close() 調用。
  3. 對比 DataOutputStream 與 ObjectOutputStream(序列化物件)差異。
  4. 閱讀 java.io 包源碼,理解 FilterInputStream 抽象裝飾基類。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved