流是 Java I/O 系統的核心抽象,無論是檔案讀寫、網路通訊還是程序間通訊,本質上都是在處理資料流。本文從基礎位元組流講起,層層遞進到字元流、緩衝流、物件序列化,構建完整知識體系。
InputStream / OutputStream所有位元組流的父類別,處理單位為「位元組」,適用於圖片、影音、二進位檔案等非文本資料。
InputStream)。OutputStream)。FileInputStream,網路用 Socket.getInputStream()。try (InputStream is = new FileInputStream("c:/boot.ini")) {
byte[] buffer = new byte[10240];
int len;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
String content = baos.toString();
System.out.println(content);
} catch (IOException e) {
e.printStackTrace();
}
關鍵點:
try-with-resources 自動關閉流(Java 7+),避免資源洩漏。buffer 批量讀寫,避免單位元組操作效能極差。read() 返回實際讀取位元組數,-1 表示流結束。try (OutputStream os = new FileOutputStream("c:/now.txt")) {
os.write(new Date().toString().getBytes());
// try-with-resources 自動 flush 並 close
} catch (IOException e) {
e.printStackTrace();
}
Reader / Writer位元組流的裝飾者,專門處理「字元」資料,內部自動處理字元編碼轉換(預設 UTF-8),適用於文本檔案。
FileReadertry (Reader reader = new FileReader("c:/boot.ini")) {
char[] buffer = new char[10240];
int count;
StringBuilder sb = new StringBuilder();
while ((count = reader.read(buffer)) != -1) {
sb.append(buffer, 0, count);
}
System.out.println(sb.toString());
}
BufferedReader 按行讀取try (BufferedReader br = new BufferedReader(new FileReader("c:/boot.ini"))) {
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
System.out.println(sb.toString());
}
BufferedReader 內部有 8KB 預設緩衝區,readLine() 直接返回一行文本,無需手動處理換行符,是讀取文本檔的標準做法。
ObjectOutputStream / ObjectInputStream將物件圖轉換為位元組序列(序列化),或從位元組序列重建物件(反序列化),支援物件持久化與網路傳輸。
Serializable 介面(標記介面,無方法)。serialVersionUID,避免版本不兼容導致 InvalidClassException。transient 關鍵字標記不序列化欄位(如密碼、暫存計算結果)。// 定義可序列化類別
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String password; // 不序列化
// 建構子、getter/setter、toString()...
}
// 序列化寫入
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("persons.data"))) {
oos.writeObject(new Person("張三", 23));
oos.writeObject(new Person("李四", 24));
}
// 反序列化讀取
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("persons.data"))) {
while (true) {
try {
Person p = (Person) ois.readObject();
System.out.println(p);
} catch (EOFException e) {
break; // 讀取結束
}
}
}
| 層級 | 輸入 | 輸出 | 適用場景 |
|---|---|---|---|
| 節點流(資料源) | FileInputStream | FileOutputStream | 檔案、記憶體陣列、網路 Socket |
| 處理流(裝飾者) | BufferedInputStream ObjectInputStream DataInputStream | BufferedOutputStream ObjectOutputStream DataOutputStream | 緩衝、物件序列化、基本類型讀寫 |
| 字元流橋接 | InputStreamReader FileReader | OutputStreamWriter FileWriter | 文本檔案處理(自動編碼轉換) |
| 字元緩衝 | BufferedReader | BufferedWriter | 高效按行讀寫文本 |
try-with-resources,確保即使拋出異常也能釋放資源。new InputStreamReader(is, "UTF-8"),避免平台預設編碼不一致導致亂碼。BufferedInputStream/BufferedReader。掌握 Java 流體系,關鍵在於理解「裝飾者模式」如何層層包裝賦予新功能,並根據資料性質選擇正確的流組合。