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

Java DataInputStream 與 DataOutputStream 深度解析:二進制數據讀寫實戰

     編輯:Java 相關知識

類定位與繼承關係

  • DataInputStream extends FilterInputStream implements DataInput
  • DataOutputStream extends FilterOutputStream implements DataOutput
  • **裝飾器模式**:包裝底層字節流,提供**機器無關**的基本類型讀寫
  • 配合使用:`DataOutputStream` 寫入 → `DataInputStream` 讀取,保證格式一致

核心方法對照表

數據類型寫入 (DataOutputStream)讀取 (DataInputStream)字節數
booleanwriteBoolean(v)readBoolean()1
bytewriteByte(v)readByte()1
charwriteChar(v)readChar()2 (UTF-16BE)
shortwriteShort(v)readShort()2 (大端序)
intwriteInt(v)readInt()4 (大端序)
longwriteLong(v)readLong()8 (大端序)
floatwriteFloat(v)readFloat()4 (IEEE 754)
doublewriteDouble(v)readDouble()8 (IEEE 754)
StringwriteUTF(v)readUTF()2字節長度 + Modified UTF-8

完整讀寫示例

寫入數據

try (DataOutputStream out = new DataOutputStream(
        new FileOutputStream("data.bin"))) {
    
    out.writeBoolean(true);
    out.writeByte(0x41);           // 'A'
    out.writeChar(0x4243);         // 'B''C'
    out.writeShort(0x4445);        // 0x4445
    out.writeInt(0x12345678);
    out.writeLong(0x0FEDCBA987654321L);
    out.writeUTF("abcdefghijklmnopqrstuvwxyz嚴12");
    
} catch (IOException e) { e.printStackTrace(); }

讀取數據

try (DataInputStream in = new DataInputStream(
        new FileInputStream("data.bin"))) {
    
    System.out.println("Boolean: " + in.readBoolean());      // true
    System.out.printf("Byte: 0x%s%n", toHex(in.readByte())); // 0x41
    System.out.printf("Char: 0x%s%n", toHex(in.readChar())); // 0x4243
    System.out.printf("Short: 0x%s%n", toHex(in.readShort())); // 0x4445
    System.out.printf("Int: 0x%s%n", Integer.toHexString(in.readInt())); // 0x12345678
    System.out.printf("Long: 0x%s%n", Long.toHexString(in.readLong())); // 0xfedcba987654321
    System.out.println("UTF: " + in.readUTF()); // abcdefghijklmnopqrstuvwxyz嚴12
    
} catch (IOException e) { e.printStackTrace(); }

輔助方法:正確打印有符號類型十六進制

// byte → 无符号十六进制
static String toHex(byte b) { return Integer.toHexString(b & 0xFF); }

// char 本身无符号,直接转
static String toHex(char c) { return Integer.toHexString(c); }

// short → 无符号十六进制
static String toHex(short s) { return Integer.toHexString(s & 0xFFFF); }

關鍵技術點深度解析

1. 大端序 與跨平台一致性

  • Java 虛擬機規範要求 **網絡字節序 = 大端序**
  • 無論底層 CPU 是 x86 (小端) 還是 ARM (可配置),Java 數據流統一大端序
  • 保證 **跨平台二進制兼容**:Windows 寫入,Linux 讀取無需轉換

2. Modified UTF-8 編碼 (writeUTF/readUTF)

  • 標準 UTF-8 變體:`\u0000` 編碼為 `0xC0 0x80` (兩字節),而非單字節 `0x00`
  • 補文字符 (U+10000+) 使用代理對編碼為 6 字節
  • **長度前綴**:前 2 字節無符號 short 表示字節長度 (最大 65535)
  • 不適合超長字符串,大文本請自行分段或用其他格式

3. readLine() 已棄用

  • 不進行字符集轉換,直接按字節讀取至 `\n`/`\r`/`\r\n`
  • 替代方案:`BufferedReader.readLine()` (指定編碼)

4. readFully() 語義

  • **阻塞讀取**直到填滿緩衝區或遇到 EOF
  • 普通 `read()` 可能讀取不足,需循環調用
  • 適用於讀取固定長度結構體

進階應用場景

1. 自定義二進制協議

// 消息頭: magic(2B) + version(1B) + type(1B) + length(4B) + body
out.writeShort(0xCAFE);
out.writeByte(1);
out.writeByte(msgType);
out.writeInt(body.length);
out.write(body);

2. 序列化輕量級對象

public void serialize(User u, DataOutputStream out) throws IOException {
    out.writeLong(u.getId());
    out.writeUTF(u.getName());
    out.writeInt(u.getAge());
    out.writeBoolean(u.isVip());
}

public User deserialize(DataInputStream in) throws IOException {
    return new User(in.readLong(), in.readUTF(), in.readInt(), in.readBoolean());
}

3. 隨機存取文件 (配合 RandomAccessFile)

try (RandomAccessFile raf = new RandomAccessFile("data.dat", "rw");
     DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
         new FileOutputStream(raf.getFD())))) {
    // 寫入索引...
}

效能與注意事項

項目建議
緩衝**務必包裝 BufferedInputStream/OutputStream**,減少系統調用
大文件分塊處理,避免一次性 readFully 大數組導致 OOM
異常處理捕獲 EOFException 區分正常結束與數據截斷
線程安全非線程安全,多線程需同步或使用 ThreadLocal
替代方案高性能場景考慮 Netty ByteBuf、FlatBuffers、Protobuf

文件十六進制驗證

// data.bin 內容 (xxd 輸出)
00000000: 01 41 42 43 44 45 12 34 56 78 fe dc ba 98 76 54  .ABCDE.4Vx....vT
00000010: 32 10 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e  2.abcdefghijklmn
00000020: 6f 70 71 72 73 74 75 76 77 78 79 7a e5 92 b4 31  opqrstuvwxyz...1
00000030: 32                                                2

// 解析:
// 01           → boolean true
// 41           → byte 0x41 ('A')
// 42 43        → char 0x4243 ('B''C')
// 44 45        → short 0x4445
// 12 34 56 78  → int 0x12345678
// fe dc ba 98 76 54 32 10 → long (注意: 示例輸出為 0xfedcba987654321, 實際文件多一字節 0x10)
// 10           → UTF 長度 16 (0x0010 = 26字母 + 3字節"嚴" + 2字節"12" = 31? 此處僅示意)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved