首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java IO 流體系全解析:節點流與處理流實戰總結

     編輯:Java 相關知識

前言

Java IO 流是文件、網絡、內存數據交換的核心抽象。本文系統梳理流分類體系、四大抽象基類、節點流與處理流組合模式、常用流實戰代碼,助你構建清晰的 IO 知識圖譜。

一、流分類體系總覽

三個維度分類

分類維度類型特點典型類
按方向輸入流數據流入程序 (read)InputStream, Reader
輸出流數據流出程序 (write)OutputStream, Writer
按數據單元字節流8-bit,處理二進制數據InputStream/OutputStream 子類
字符流16-bit Unicode,處理文本Reader/Writer 子類
按功能角色節點流直接操作數據源/目的地FileInputStream, FileReader
處理流包裝其他流,提供增強功能BufferedInputStream, InputStreamReader

四大抽象基類


                    java.lang.Object
                          │
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
  InputStream       OutputStream         Reader ← Writer
  (字節輸入)         (字節輸出)           (字符輸入)  (字符輸出)
        │                 │                 │          │
  ┌─────┴─────┐     ┌─────┴─────┐     ┌─────┴────┐ ┌──┴────┐
  ▼           ▼     ▼           ▼     ▼          ▼ ▼       ▼
File...   Buffer...  File...   Buffer...  File... Buffer... Print...

二、節點流:直連數據源

數據源類型字節流字符流
文件FileInputStream / FileOutputStreamFileReader / FileWriter
內存數組ByteArrayInputStream / ByteArrayOutputStreamCharArrayReader / CharArrayWriter
字符串-StringReader / StringWriter
管道PipedInputStream / PipedOutputStreamPipedReader / PipedWriter

文件複製基礎示例


public void copyFileBasic(String src, String dest) throws IOException {
    try (FileInputStream fis = new FileInputStream(src);
         FileOutputStream fos = new FileOutputStream(dest)) {
        byte[] buffer = new byte[8192];
        int len;
        while ((len = fis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
    } // try-with-resources 自動關閉
}

三、處理流:裝飾者模式賦能

核心處理流分類

功能字節流字符流核心作用
緩衝BufferedInputStream/OutputStreamBufferedReader/Writer減少系統調用,提升性能
轉換-InputStreamReader/OutputStreamWriter字節↔字符,指定編碼
數據類型DataInputStream/OutputStream-基本類型序列化
對象序列化ObjectInputStream/OutputStream-對象圖持久化
打印PrintStreamPrintWriter格式化輸出、自動 flush
推回PushbackInputStreamPushbackReader預讀一字節/字符

四、實戰核心場景代碼

1. 緩衝流:性能加速器


public void bufferedCopy(String src, String dest) throws IOException {
    // 字節緩衝:適用於二進制文件(圖片、視頻)
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest))) {
        byte[] buf = new byte[8192];
        int len;
        while ((len = bis.read(buf)) != -1) {
            bos.write(buf, 0, len);
        }
        bos.flush(); // 關鍵:強制刷新緩衝區
    }
    
    // 字符緩衝:適用於文本文件,支持按行讀寫
    try (BufferedReader br = new BufferedReader(new FileReader(src));
         BufferedWriter bw = new BufferedWriter(new FileWriter(dest))) {
        String line;
        while ((line = br.readLine()) != null) {
            bw.write(line);
            bw.newLine(); // 跨平台換行符
        }
        bw.flush();
    }
}

2. 轉換流:編碼橋樑


public void encodingDemo() throws IOException {
    // 寫入指定編碼
    try (OutputStreamWriter osw = new OutputStreamWriter(
            new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8)) {
        osw.write("中文測試");
    }
    
    // 讀取指定編碼
    try (InputStreamReader isr = new InputStreamReader(
            new FileInputStream("gbk.txt"), "GBK")) {
        char[] buf = new char[1024];
        int len = isr.read(buf);
        System.out.println(new String(buf, 0, len));
    }
    
    // 系統默認編碼查看
    System.out.println("default charset: " + Charset.defaultCharset());
}

3. 數據流:基本類型二進制存儲


public void dataStreamDemo() throws IOException {
    // 寫入
    try (DataOutputStream dos = new DataOutputStream(
            new BufferedOutputStream(new FileOutputStream("data.bin")))) {
        dos.writeInt(12345);
        dos.writeDouble(3.14159);
        dos.writeBoolean(true);
        dos.writeUTF("Hello World"); // 修改 UTF-8 字符串
        dos.flush();
    }
    
    // 讀取:順序必須與寫入一致!
    try (DataInputStream dis = new DataInputStream(
            new BufferedInputStream(new FileInputStream("data.bin")))) {
        int i = dis.readInt();       // 12345
        double d = dis.readDouble(); // 3.14159
        boolean b = dis.readBoolean(); // true
        String s = dis.readUTF();    // "Hello World"
    }
}

4. 打印流:便捷輸出


public void printStreamDemo() throws IOException {
    // 重定向 System.out 到文件
    try (PrintStream ps = new PrintStream(
            new FileOutputStream("log.txt"), true, StandardCharsets.UTF_8)) {
        System.setOut(ps);
        System.out.println("這行輸出到文件了");
        System.out.printf("格式化: %d, %.2f%n", 42, 3.14);
        // 自動 flush (第二個參數 true)
    }
    
    // PrintWriter 更靈活
    try (PrintWriter pw = new PrintWriter(
            new OutputStreamWriter(new FileOutputStream("log2.txt"), "UTF-8"), true)) {
        pw.println("PrintWriter 也支援自動 flush");
    }
}

5. 對象序列化流


@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
    private transient String password; // 不序列化
}

public void objectStreamDemo() throws IOException, ClassNotFoundException {
    User user = new User(1, "Alice", "secret123");
    
    // 序列化
    try (ObjectOutputStream oos = new ObjectOutputStream(
            new BufferedOutputStream(new FileOutputStream("user.ser")))) {
        oos.writeObject(user);
    }
    
    // 反序列化
    try (ObjectInputStream ois = new ObjectInputStream(
            new BufferedInputStream(new FileInputStream("user.ser")))) {
        User restored = (User) ois.readObject();
        // restored.password 為 null (transient)
    }
}

五、流組合模式最佳實踐

標準組合鏈


// 讀取文本文件:節點流 → 緩衝流 → 轉換流(可選)
BufferedReader reader = new BufferedReader(
    new InputStreamReader(
        new FileInputStream("file.txt"), StandardCharsets.UTF_8));

// 寫入二進制文件:節點流 → 緩衝流 → 數據流(可選)
DataOutputStream writer = new DataOutputStream(
    new BufferedOutputStream(
        new FileOutputStream("data.bin")));

// 對象序列化:節點流 → 緩衝流 → 對象流
ObjectOutputStream oos = new ObjectOutputStream(
    new BufferedOutputStream(
        new FileOutputStream("obj.ser")));

關鍵原則

  1. 關閉最外層流:會級聯關閉內層流
  2. try-with-resources:Java 7+ 必須使用,防止洩漏
  3. 緩衝流必須 flush:寫入完成前數據在內存
  4. 指定編碼:避免平台默認編碼差異導致亂碼

六、NIO.2 現代化文件操作 (Java 7+)


public void nio2Demo() throws IOException {
    Path path = Paths.get("data.txt");
    
    // 一行代碼讀寫
    List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
    Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
    
    // 流式處理大文件
    try (Stream<String> stream = Files.lines(path)) {
        stream.filter(s -> s.contains("ERROR"))
              .forEach(System.out::println);
    }
    
    // 文件屬性
    BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
    System.out.println("創建時間: " + attrs.creationTime());
    System.out.println("大小: " + attrs.size());
    
    // 目錄遍歷
    Files.walk(Paths.get("."))
         .filter(p -> p.toString().endsWith(".java"))
         .forEach(System.out::println);
}

七、性能優化清單

場景建議原因
大文件複製FileChannel.transferTo/transferFrom零拷貝,內核態完成
頻繁小量讀寫Buffered 流 + 8KB-64KB 緩衝區減少系統調用
文本處理BufferedReader.readLine / Files.lines按行處理,內存友好
對象傳輸Protobuf/Kryo/Hessian 替代 JDK 序列化體積小、速度快、跨語言
高併發日誌異步寫入 + 批量刷新 (Logback/Log4j2)不阻塞業務線程

八、常見坑點

  1. 忘記 flush:數據停留在緩衝區,文件為空或不全
  2. 編碼不一致:寫 UTF-8 讀 GBK → 亂碼
  3. 流未關閉:文件句柄洩漏,導致「Too many open files」
  4. 序列化版本不兼容:修改類結構未更新 serialVersionUID → InvalidClassException
  5. 裝飾順序錯誤:DataOutputStream 包裝 BufferedOutputStream 而非相反

總結

Java IO 流採用裝飾者模式實現功能組合。掌握四大基類、節點流與處理流職責分工、標準組合鏈、編碼處理、序列化機制、NIO.2 現代 API,即可應對絕大多數 IO 場景。性能敏感場景優先考慮 NIO 零拷貝、異步 IO 或成熟日誌框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved