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

【Java I/O】位元組流 InputStream/OutputStream 體系全解析與實戰範例

     編輯:Java 綜合教學

前言

位元組流是 Java I/O 的基石,處理圖片、影音、序列化資料、網路通訊等所有二進位資料。本文系統梳理 InputStream/OutputStream 核心子類用途、裝飾者模式應用、完整程式碼範例與選型指南。

一、核心子類用途總覽

類別用途關鍵特性
ByteArrayInputStream/OutputStream記憶體位元組陣列 ↔ 流無 I/O 裝置存取,單元測試、緩衝轉換常用
FileInputStream/OutputStream本地檔案讀寫最基礎檔案流,無緩衝,大檔案需包裝
PipedInputStream/OutputStream執行緒管道通訊 (位元組)同一 JVM,生產者/消費者,阻塞式
BufferedInputStream/OutputStream為任意位元組流增加緩衝裝飾者模式,預設 8KB,大幅提升效能
FilterInputStream/OutputStream自訂過濾裝飾基類單純委派,實務極少直接用
PushbackInputStream支援「退回」一個位元組解析器需預讀一字元再推回
DataInputStream/OutputStream讀寫 Java 基本型別 (跨平台二進位)支援 readInt()/writeDouble() 等,大端序
PrintStream格式化輸出至位元組流System.out 即此類,printf/println,吞噬異常
ObjectInputStream/OutputStream物件序列化/反序列化需實作 Serializable,版本控制 serialVersionUID
SequenceInputStream串聯多個 InputStream依序讀完第一個再讀第二個,合併多源

二、類別結構圖

InputStream/OutputStream 類別結構

三、實戰範例精選

1. ByteArray 流互轉

byte[] src = {1, 2, 3};
try (InputStream is = new ByteArrayInputStream(src);
     ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
    byte[] buf = new byte[3];
    is.read(buf);           // 讀入陣列
    bos.write(buf);         // 寫入輸出流
    byte[] dest = bos.toByteArray(); // 取回陣列
    System.out.println(Arrays.toString(dest)); // [1, 2, 3]
}

2. 檔案複製 (基礎版 vs 緩衝版)

// 基礎版:逐位元組,極慢
try (InputStream is = new FileInputStream("src.jpg");
     OutputStream os = new FileOutputStream("dest.jpg")) {
    int b;
    while ((b = is.read()) != -1) os.write(b);
}

// 緩衝版:生產環境標準寫法
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src.jpg"), 64*1024);
     BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("dest.jpg"), 64*1024)) {
    byte[] buf = new byte[8192];
    int len;
    while ((len = bis.read(buf)) != -1) bos.write(buf, 0, len);
}

3. 執行緒管道通訊

PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(() -> { try { pos.write(new byte[]{1,2,3}); pos.close(); } catch (IOException e) { e.printStackTrace(); }});
es.submit(() -> { try { byte[] b = new byte[3]; pis.read(b); System.out.println(Arrays.toString(b)); } catch (IOException e) { e.printStackTrace(); }});
es.shutdown();

4. PushbackInputStream 預讀退回

PushbackInputStream pis = new PushbackInputStream(new ByteArrayInputStream(new byte[]{1,2,3}));
System.out.println(pis.read()); // 1
System.out.println(pis.read()); // 2
pis.unread(2);                  // 退回 '2'
System.out.println(pis.read()); // 2 (再次讀到)
pis.close();

5. Data 流讀寫基本型別

try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"));
     DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
    dos.writeDouble(2.0235);
    dos.writeInt(520);
    dos.flush();
    System.out.println(dis.readDouble()); // 2.0235
    System.out.println(dis.readInt());    // 520
}

6. PrintStream 格式化輸出

PrintStream ps = System.out; // 已是 PrintStream
ps.printf("編號: %05d, 價格: %.2f%n", 101, 99.9);
ps.println("自動換行");

7. 物件序列化 (Object 流)

class Dog implements Serializable {
    private static final long serialVersionUID = 1L;
    private int age;
    public Dog(int age) { this.age = age; }
    public int getAge() { return age; }
}
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog.obj"));
     ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog.obj"))) {
    oos.writeObject(new Dog(2));
    oos.flush();
    Dog d = (Dog) ois.readObject();
    System.out.println(d.getAge()); // 2
}

8. SequenceInputStream 合併多源

SequenceInputStream sis = new SequenceInputStream(
    new ByteArrayInputStream(new byte[]{1,2,3}),
    new ByteArrayInputStream(new byte[]{4,5,6})
);
byte[] buf = new byte[3];
sis.read(buf); // [1,2,3]
sis.read(buf); // [4,5,6] (自動切換第二個流)
sis.close();

四、選型決策樹

  1. 資料來源/目的地是檔案?→ FileInputStream/OutputStream (必包 Buffered)。
  2. 資料在記憶體陣列?→ ByteArrayInputStream/OutputStream。
  3. 需執行緒間傳遞?→ PipedInputStream/OutputStream。
  4. 需讀寫 int/double/boolean 等基本型別?→ DataInputStream/OutputStream。
  5. 需序列化物件?→ ObjectInputStream/OutputStream (實作 Serializable)。
  6. 需格式化列印?→ PrintStream (或 PrintWriter 處理字元)。
  7. 需合併多個輸入源?→ SequenceInputStream。
  8. 需預讀一字節再退回?→ PushbackInputStream。

五、最佳實踐備忘錄

  • 永遠使用 try-with-resources (JDK 7+),確保 close() 執行釋放檔案鎖。
  • 大檔案必加緩衝:BufferedInputStream/OutputStream 或 NIO FileChannel.transferTo() (零拷貝,更快)。
  • 指定緩衝區大小:64KB~256KB 適合磁碟 I/O;網路流可依 MTU 調整。
  • 序列化類必宣告 serialVersionUID:避免版本不一致導致 InvalidClassException。
  • 區分位元組 vs 字元:文字檔請用 Reader/Writer 體系 (含編碼轉換);二進位檔用 InputStream/OutputStream。
  • PrintStream 不拋 IOException:關鍵輸出請用 PrintWriter 或手動 checkError()。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved