| 分類維度 | 類別 | 代表類 | 核心特徵 |
|---|---|---|---|
| 按數據類型 | 字節流 | InputStream / OutputStream | 處理二進制:圖片、視頻、音頻、序列化對象 |
| 字符流 | Reader / Writer | 處理文本:txt、JSON、XML、CSV (內部按 char[] 處理) | |
| 按流向 | 輸入流 | InputStream / Reader | 設備 → 內存 (read) |
| 輸出流 | OutputStream / Writer | 內存 → 設備 (write) | |
| 按封裝層級 | 節點流/原始流 | FileInputStream, FileReader | 直接連接數據源,構造器不接受其他流 |
| 處理流/包裝流 | BufferedInputStream, InputStreamReader | 包裝其他流,提供緩衝、轉碼、對象化等增強功能 | |
| 按功能 | 基礎流 | File, ByteArray, Piped | 直接操作具體設備/內存 |
| 工具流 | Data, Object, Print, Buffered | 提供特定數據類型讀寫、緩衝、格式化等能力 |
java.io.InputStream (抽象)
├── FileInputStream // 文件字節輸入
├── ByteArrayInputStream // 內存字節數組輸入
├── FilterInputStream // 過濾器基類
│ ├── BufferedInputStream // 緩衝輸入 (核心:8KB 默認緩衝區)
│ ├── DataInputStream // 基本類型讀取 (readInt, readUTF...)
│ └── ObjectInputStream // 對象反序列化
├── PipedInputStream // 管道輸入
└── SequenceInputStream // 串聯多個輸入流
java.io.Reader (抽象)
├── FileReader // 文件字符輸入 (默認平台編碼)
├── InputStreamReader // 字節→字符轉換橋樑 (關鍵:指定編碼)
│ └── FileReader 實際繼承此類
├── BufferedReader // 緩衝字符輸入 (核心:readLine())
└── CharArrayReader // 字符數組輸入
OutputStream / Writer 體系對稱...
public static void copyFileBytes(String src, String dest) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest)) {
byte[] buffer = new byte[8192]; // 8KB 緩衝區
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
}
// 方式一:Files.readString (Java 11+, 最簡潔)
String content = Files.readString(Paths.get("file.txt"), StandardCharsets.UTF_8);
// 方式二:BufferedReader 逐行讀取 (經典,大文件友好)
public static List readLines(String path, String charset) throws IOException {
List lines = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(path), charset))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
// 方式三:Scanner (簡單解析)
try (Scanner scanner = new Scanner(new File("data.txt"), "UTF-8")) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
// 字節緩衡 - 複制大文件
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
byte[] buf = new byte[16384];
int len;
while ((len = in.read(buf)) != -1) out.write(buf, 0, len);
}
// 字符緩衡 - 逐行處理
try (BufferedReader br = new BufferedReader(new FileReader("log.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(processLine(line));
bw.newLine(); // 跨平台換行
}
}
// 讀取 GBK 文件
try (Reader reader = new InputStreamReader(new FileInputStream("gbk.txt"), "GBK")) {
// ...
}
// 寫入 UTF-8 文件
try (Writer writer = new OutputStreamWriter(new FileOutputStream("utf8.txt"), "UTF-8")) {
// ...
}
// 系統默認編碼陷阱
// FileReader / FileWriter 使用平台默認編碼,跨平台會亂碼
// 強烈建議:顯式使用 InputStreamReader/OutputStreamWriter 指定編碼
// 寫入
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
dos.writeInt(100);
dos.writeDouble(3.14);
dos.writeUTF("Hello");
dos.writeBoolean(true);
}
// 讀取 (順序必須一致)
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
int i = dis.readInt();
double d = dis.readDouble();
String s = dis.readUTF();
boolean b = dis.readBoolean();
}
// 實現 Serializable 接口
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private transient String password; // transient 不序列化
// getter/setter...
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.obj"))) {
oos.writeObject(new User("admin", "secret"));
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.obj"))) {
User user = (User) ois.readObject();
}
try (PrintWriter pw = new PrintWriter(new FileWriter("report.txt"))) {
pw.printf("用戶: %s, 年齡: %d, 薪資: %.2f%n", "張三", 25, 8500.0);
pw.println("--- 分割線 ---");
pw.format(Locale.CHINA, "金額: %,.2f 元%n", 1234567.89);
}
// 字節數組流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 寫入數據...
byte[] data = baos.toByteArray();
// 字符數組流
CharArrayWriter caw = new CharArrayWriter();
// 寫入字符...
String str = caw.toString();
// 字符串流 (僅讀)
try (Reader reader = new StringReader("line1\nline2")) {
// ...
}
// 簡單複製
Files.copy(Paths.get(src), Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
// 帶進度回調
Files.copy(Paths.get(src), Paths.get(dest),
StandardCopyOption.REPLACE_EXISTING,
(bytesCopied, totalBytes) -> System.out.printf("進度: %.1f%%%n", bytesCopied*100.0/totalBytes));
// 移動/重命名 (原子操作)
Files.move(Paths.get(src), Paths.get(dest), StandardCopyOption.ATOMIC_MOVE);
// 錯誤
FileInputStream in = new FileInputStream("a.txt");
// 異常拋出時流未關閉
// 正確:try-with-resources (Java 7+)
try (FileInputStream in = new FileInputStream("a.txt")) {
// 自動關閉,即使拋異常
}
// 危險:Windows(GBK) 寫入,Linux(UTF-8) 讀取 → 亂碼
new FileWriter("a.txt").write("中文");
// 安全:顯式指定 UTF-8
new OutputStreamWriter(new FileOutputStream("a.txt"), StandardCharsets.UTF_8).write("中文");
// 錯誤:以 0 為結束標誌
while ((b = in.read()) != 0) { ... } // 0 是合法字節!
// 正確:-1 表示結束
while ((b = in.read()) != -1) { ... }
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
bw.write("重要數據");
// 程序異常退出,數據仍在緩衝區,文件為空!
// 正確:關閉流自動 flush,或關鍵點手動 flush
bw.flush();
// 危險:一次性讀入內存
byte[] all = Files.readAllBytes(Paths.get("10GB.log"));
// 安全:流式處理
Files.lines(Paths.get("10GB.log")).forEach(line -> process(line));
// 修改類結構後反序列化舊數據拋 InvalidClassException
// 必須顯式聲明
private static final long serialVersionUID = 1L;
new BufferedInputStream(in, 65536)FileChannel.transferTo() 零拷貝,大文件傳輸最快ByteBuffer.allocateDirect() 避免堆外/堆內拷貝AsynchronousFileChannel (Java 7+) 高併發場景FileChannel.map() 隨機訪問大文件Java IO 體系雖龐大,但掌握 字節/字符雙軌、裝飾器模式包裝增強、try-with-resources 自動資源管理 三大核心,即可應對 95% 場景。現代開發首選 java.nio.file.Files 靜態工具類簡化常見操作,複雜場景組合 BufferedInputStream/Reader + 顯式編碼。記住:流用完必關,編碼必顯式,大文件必流式。