| 流類型 | 輸入基類 | 輸出基類 | 最小單位 |
|---|---|---|---|
| 位元組流 | InputStream | OutputStream | byte (8 bits) |
| 字元流 | Reader | Writer | char (16 bits Unicode) |
所有具體流類均繼承自這四個抽象類。Reader/Writer 是 JDK 1.1 引入,補充字元處理能力;兩者介面完全對稱(read()/write() 重載)。
FileInputStream、ByteArrayInputStream、PipedInputStream。BufferedInputStream、DataInputStream、InputStreamReader。實戰鐵律:幾乎不直接使用節點流,而是層層包裝:
// 典型:檔案 → 緩衝 → 字元轉換 → 行讀取
BufferedReader in = new BufferedReader(
new InputStreamReader(
new FileInputStream("data.txt"), "UTF-8"));
| 來源/目的地 | 位元組流 | 字元流 |
|---|---|---|
| 檔案 | FileInputStream / FileOutputStream | FileReader / FileWriter |
| 記憶體陣列 | ByteArrayInputStream / ByteArrayOutputStream | CharArrayReader / CharArrayWriter |
| 字串 | — | StringReader / StringWriter |
| 管道(執行緒間) | PipedInputStream / PipedOutputStream | PipedReader / PipedWriter |
// 位元組流 → 字元流(解碼)
InputStreamReader isr = new InputStreamStream(inputStream, "UTF-8");
// 字元流 → 位元組流(編碼)
OutputStreamWriter osw = new OutputStreamWriter(outputStream, "UTF-8");
必須顯式指定 charset,避免平台預設編碼(Windows GBK、Linux UTF-8)導致亂碼。
public static String readFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) sb.append(line).append('\n');
return sb.toString();
}
}
public static void writeWithLineNumber(String src, String dest) throws IOException {
try (BufferedReader br = new BufferedReader(new StringReader(src));
PrintWriter pw = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(dest), StandardCharsets.UTF_8)))) {
String line; int n = 1;
while ((line = br.readLine()) != null) pw.println(n++ + ": " + line);
}
}
PrintStream console = System.out;
try (PrintStream fileOut = new PrintStream(
new BufferedOutputStream(new FileOutputStream("out.txt")), true, "UTF-8")) {
System.setOut(fileOut);
System.out.println("這行寫入檔案");
} finally {
System.setOut(console); // 恢復
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream("obj.dat")))) {
oos.writeObject(userObject);
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(new FileInputStream("obj.dat")))) {
User u = (User) ois.readObject();
}
注意:實作 Serializable,敏感欄位用 transient 排除。序列化會遞歸包含引用物件圖,支援深拷貝。
try (RandomAccessFile raf = new RandomAccessFile("data.dat", "rw")) {
raf.seek(100); // 跳到位元組 100
raf.writeDouble(3.14);
raf.seek(100);
double d = raf.readDouble();
}
大檔案隨機讀寫首選;現代替代方案:MappedByteBuffer (NIO 記憶體映射)。
BufferedInputStream/BufferedReader 減少系統呼叫。byte[]/char[] 緩衝區,避免單位元組/字元操作。Files.readAllLines()、Files.newBufferedReader()、FileChannel 映射更高效。