除了常用的字節流、字符流、緩沖流,Java 提供了三類特殊流解決特定場景:對象序列化流 (持久化對象)、轉換流 (字節↔字符編碼橋梁)、隨機訪問流 (文件指針定位)。本文逐一拆解原理與代碼實戰。
// 實體類
class Student implements Serializable {
private String name; private int age;
// 構造、get/set、toString...
// 關鍵:建議顯式聲明 serialVersionUID
private static final long serialVersionUID = 1L;
}
// 序列化
Student stu = new Student("zhangsan", 30);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/test.txt"))) {
oos.writeObject(stu);
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/test.txt"))) {
Student stu2 = (Student) ois.readObject();
System.out.println(stu2); // Student [name=zhangsan, age=30]
}
修改類結構 (如新增字段) 後反序列化舊數據會拋 `InvalidClassException` (serialVersionUID 不匹配)。
Add default serial version ID 或 Add generated serial version ID。| 編碼 | 特點 |
|---|---|
| ASCII | 7位,128字符,英數符號 |
| ISO-8859-1 | 8位,西歐語言 |
| GB2312 | 中文標準,6763漢字 |
| GBK | GB2312超集,含生僻字、繁體 |
| Unicode (UTF-16) | 固定2字節,Java 內部編碼 |
| UTF-8 | 可變長(1-4字節),兼容 ASCII,網頁首選 |
// 寫入 (指定 UTF-8)
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("d:/code.txt"), "UTF-8"))) {
bw.write("你好");
}
// 讀取 (指定 UTF-8)
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("d:/code.txt"), "UTF-8"))) {
String line;
while ((line = br.readLine()) != null) System.out.println(line);
}
"r" (只讀)、"rw" (讀寫)。class Person {
private String name; // 固定15字符
private int age;
public static int SIZE = 34; // 每條記錄固定字節數
// 構造時用 StringBuilder 固定長度,不足補 '\u0000'
public Person(String name, int age) {
StringBuilder sb = new StringBuilder(name != null ? name : "");
sb.setLength(15); this.name = sb.toString(); this.age = age;
}
// 讀取輔助:讀15字符並替換 '\u0000' 為空格
static String readName(RandomAccessFile raf) throws IOException {
char[] cs = new char[15];
for (int i=0; i<15; i++) cs[i] = raf.readChar();
return new String(cs).replace('\u0000', ' ');
}
}
// 寫入多條記錄
Person[] persons = {new Person("zhangsan",10), new Person("lisi",24), ...};
try (RandomAccessFile raf = new RandomAccessFile("d:/test2.txt", "rw")) {
for (Person p : persons) {
raf.writeChars(p.getName()); // 30字節
raf.writeInt(p.getAge()); // 4字節
}
}
// 隨機讀取第 N 條 (從0開始)
int n = 2; // 讀取第3條
raf.seek(n * Person.SIZE); // 移動指針
Person p = new Person();
p.setName(readName(raf));
p.setAge(raf.readInt());
System.out.println(p); // 姓名: lisi 年齡: 24
| 流類型 | 核心場景 | 關鍵點 |
|---|---|---|
| ObjectInput/OutputStream | 對象持久化、網絡傳輸、深拷貝 | 實現 Serializable、聲明 serialVersionUID、處理版本演進 |
| InputStreamReader/OutputStreamWriter | 指定編碼讀寫文本文件、網絡通信編解碼 | 字節↔字符橋梁、必須指定 charset、配合 BufferedReader/Writer 提效 |
| RandomAccessFile | 大文件隨機讀寫、定長記錄存取、斷點續傳 | 文件指針 seek()、rw 模式、非線程安全、非 NIO (Channel 更高性能) |