Java I/O 體系中,除了處理位元組流與字元流,針對基本資料型別與字串的資料操作同樣重要。本文深入解析 DataInputStream 與 DataOutputStream 的核心機制,並透過完整的 Account 類別範例,示範如何手動實作物件序列化與反序列化,為資料傳輸與持久化奠定基礎。
Java 提供兩個關鍵類別處理基本型別資料流:
DataOutput 介面,提供 writeInt()、writeUTF() 等寫入方法DataInput 介面,提供 readInt()、readUTF() 等讀取方法這兩個介面定義了將位元組流轉換為 Java 基本型別(byte、int、char、long、float、double、boolean、short)與 String 的標準契約。值得注意的是,RandomAccessFile 同時實作了這兩個介面,使其能對同一檔案進行隨機讀寫。
所有方法遵循 readXXX()/writeXXX() 命名模式,其中 XXX 代表型別名稱。特別的是 readUTF()/writeUTF() 採用修改版 UTF-8 編碼儲存字串,支援國際化字元集。
以下展示一個完整的帳戶資料類別,包含建構子、序列化、反序列化與除錯方法:
package com.j2medev.mingjava;
import java.io.*;
public class Account {
private String userName = "";
private String email = "";
private int age = 0;
private boolean gender = false;
// 無參建構子(反序列化必需)
public Account() {}
// 完整建構子
public Account(String userName, String email, int age, boolean gender) {
this.userName = userName;
this.email = email;
this.age = age;
this.gender = gender;
}
// 序列化:依固定順序寫入資料流
public void serialize(DataOutputStream dos) throws IOException {
dos.writeUTF(userName);
dos.writeUTF(email);
dos.writeInt(age);
dos.writeBoolean(gender);
}
// 反序列化:嚴格遵循相同順序讀取
public static Account deserialize(DataInputStream dis) throws IOException {
Account account = new Account();
account.userName = dis.readUTF();
account.email = dis.readUTF();
account.age = dis.readInt();
account.gender = dis.readBoolean();
return account;
}
// 除錯用字串表示
@Override
public String toString() {
return "UserName = " + userName + " Email = " + email +
" age = " + age + " gender = " + (gender ? "male" : "female");
}
}
deserialize() 設計為靜態方法,回傳新建立的物件實例IOException,由呼叫端統一處理 I/O 錯誤測試程式使用 ByteArrayOutputStream 進行記憶體內序列化,避免檔案 I/O 干擾核心邏輯驗證:
public class TestDataIO {
public static void main(String[] args) throws IOException {
// 建立測試物件
Account account = new Account("mingjava", "eric.zhan@263.net", 25, true);
System.out.println("before serialization.........");
System.out.println(account);
// 序列化到記憶體緩衝區
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) {
account.serialize(dos);
// 反序列化驗證
try (DataInputStream dis = new DataInputStream(
new ByteArrayInputStream(baos.toByteArray()))) {
Account restored = Account.deserialize(dis);
System.out.println("after serialization..........");
System.out.println(restored);
}
}
}
}
before serialization.........
UserName = mingjava Email = eric.zhan@263.net age = 25 gender = male
after serialization..........
UserName = mingjava Email = eric.zhan@263.net age = 25 gender = male
手動序列化在資源受限環境(如早期 J2ME)極具價值,可避開 Java 原生序列化的體積開銷,精確控制傳輸協定格式。
BufferedOutputStream 包裝底層輸出流減少系統呼叫ObjectOutputStream 原生序列化或 Protobuf 等高效協定掌握 DataInputStream/DataOutputStream 的手動序列化技術,不僅能深入理解資料在記憶體與持久層間的轉換本質,更能在特定場景(嵌入式系統、自訂網路協定、跨語言互操作)發揮關鍵作用。雖然現代框架多採用 JSON、Protobuf 等高層協定,但底層二進位流操作能力仍是 Java 開發者的核心內功。