当前位置: 首页 > news >正文

数据类型处理流讲解

DataInputStreamDataOutputStream 是 Java I/O 中处理基本数据类型的核心工具,它们允许你直接读写原始数据类型(如 int, double, boolean 等),而不是只处理字节或字符。这两个类属于过滤流,需要包装在字节流上使用。

一、核心功能与特点

DataOutputStream 核心功能

// 写入各种基本数据类型
void writeBoolean(boolean v)
void writeByte(int v)      // 写入8位
void writeShort(int v)     // 写入16位
void writeChar(int v)      // 写入16位字符
void writeInt(int v)       // 写入32位整数
void writeLong(long v)     // 写入64位长整数
void writeFloat(float v)   // 写入32位浮点数
void writeDouble(double v) // 写入64位双精度
void writeUTF(String str)  // 写入UTF-8编码字符串

DataInputStream 核心功能

// 读取各种基本数据类型
boolean readBoolean()
byte readByte()
short readShort()
char readChar()
int readInt()
long readLong()
float readFloat()
double readDouble()
String readUTF()  // 读取UTF-8字符串

关键特性

  1. 二进制格式:数据以紧凑二进制存储(非人类可读)

  2. 平台无关:使用大端序(Big-Endian),保证跨平台一致性

  3. 类型安全:严格区分数据类型

  4. 高效存储:比文本格式节省50-75%空间

  5. 流装饰:必须包装在基础字节流上使用

二、使用示例:读写混合数据类型

写入数据示例

try (DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.bin")))) {// 写入各种类型数据dos.writeUTF("用户数据"); // UTF字符串dos.writeInt(1001);      // 用户IDdos.writeBoolean(true);  // 激活状态dos.writeDouble(1250.75);// 账户余额dos.writeUTF("2023-10-01"); // 日期// 写入数组int[] scores = {85, 92, 78};dos.writeInt(scores.length); // 先写长度for (int score : scores) {dos.writeInt(score);}
}

读取数据示例

try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("data.bin")))) {// 按写入顺序读取String title = dis.readUTF();int userId = dis.readInt();boolean isActive = dis.readBoolean();double balance = dis.readDouble();String date = dis.readUTF();// 读取数组int length = dis.readInt();int[] scores = new int[length];for (int i = 0; i < length; i++) {scores[i] = dis.readInt();}System.out.println(title);System.out.println("用户ID: " + userId);System.out.println("激活状态: " + isActive);System.out.printf("余额: $%.2f%n", balance);System.out.println("最后登录: " + date);System.out.println("分数: " + Arrays.toString(scores));
}

三、底层数据格式解析

1. 基本数据类型存储大小

数据类型大小 (字节)存储格式
boolean10x00(false) 或 0x01(true)
byte1原始8位值
short2大端序16位整数
char2UTF-16编码单元
int4大端序32位整数
long8大端序64位整数
float4IEEE 754 单精度浮点
double8IEEE 754 双精度浮点
String(UTF)2 + n前2字节为长度,后跟UTF-8

2. 文件结构示例

文件: data.bin 的二进制结构
​
00000000: 00 0C 用户数据   // UTF头: 00 0C = 12字节长度
0000000C: 00 00 03 E9     // int 1001 (0x3E9)
00000010: 01              // boolean true
00000011: 40 93 86 00 00 00 00 00 // double 1250.75
00000019: 00 0A 2023-10-01 // 10字节日期字符串
00000023: 00 00 00 03     // 数组长度3
00000027: 00 00 00 55     // 85
0000002B: 00 00 00 5C     // 92
0000002F: 00 00 00 4E     // 78

四、高级应用技巧

1. 自定义数据序列化

// 序列化用户对象
public void writeUser(User user, DataOutputStream dos) throws IOException {dos.writeUTF(user.getName());dos.writeInt(user.getAge());dos.writeDouble(user.getSalary());dos.writeBoolean(user.isMarried());
}
​
// 反序列化
public User readUser(DataInputStream dis) throws IOException {return new User(dis.readUTF(),dis.readInt(),dis.readDouble(),dis.readBoolean());
}

2. 数据对齐与填充

// 固定长度记录写入
public void writeFixedRecord(DataOutputStream dos, Record record) throws IOException {dos.writeInt(record.getId());dos.writeUTF(record.getName());// 填充剩余空间int bytesWritten = 4 + 2 + record.getName().getBytes(StandardCharsets.UTF_8).length;int padding = 100 - bytesWritten; // 每条记录100字节for (int i = 0; i < padding; i++) {dos.writeByte(0); // 填充空字节}
}

3. 二进制数据校验

// 写入带校验和的数据
public void writeWithChecksum(DataOutputStream dos, byte[] data) throws IOException {// 计算校验和int checksum = 0;for (byte b : data) {checksum += b & 0xFF;}dos.writeInt(data.length);dos.write(data);dos.writeInt(checksum);
}
​
// 读取并验证
public byte[] readWithChecksum(DataInputStream dis) throws IOException {int length = dis.readInt();byte[] data = new byte[length];dis.readFully(data); // 读取完整字节数组int expectedChecksum = dis.readInt();int actualChecksum = 0;for (byte b : data) {actualChecksum += b & 0xFF;}if (actualChecksum != expectedChecksum) {throw new IOException("数据校验失败");}return data;
}

五、性能优化实践

1. 批量读写优化

// 批量写入整数数组
public void writeIntArray(DataOutputStream dos, int[] array) throws IOException {dos.writeInt(array.length);for (int i = 0; i < array.length; i += 1024) {int chunkSize = Math.min(1024, array.length - i);// 逐个写入比写入字节数组慢10倍for (int j = 0; j < chunkSize; j++) {dos.writeInt(array[i + j]);}}
}

2. 内存映射文件加速

// 使用MappedByteBuffer处理大数据
try (RandomAccessFile raf = new RandomAccessFile("bigdata.bin", "rw")) {MappedByteBuffer buffer = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1024 * 1024 * 100); // 100MB// 直接操作缓冲区while (buffer.hasRemaining()) {int value = buffer.getInt();// 处理数据...}
}

六、使用注意事项

  1. 严格顺序匹配

    // 写入顺序
    dos.writeUTF(name);
    dos.writeInt(age);
    ​
    // 读取必须相同顺序
    String n = dis.readUTF();
    int a = dis.readInt(); 
  2. EOF处理

    try {while (true) {String data = dis.readUTF();// 处理数据}
    } catch (EOFException e) {// 正常结束:文件读取完毕
    }
  3. 字符编码问题

    // 错误:直接处理非ASCII字符
    dos.writeChars("中文"); // 使用UTF-16,浪费空间
    ​
    // 正确:统一使用UTF-8
    dos.writeUTF("中文"); // 更紧凑的UTF-8
  4. 字节序问题

    // 如需小端序处理,使用ByteBuffer转换
    ByteBuffer buffer = ByteBuffer.allocate(4);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    buffer.putInt(value);
    dos.write(buffer.array());

七、适用场景对比

场景推荐方案优点缺点
配置文件Properties类人类可读,易修改效率低,无类型信息
简单文本数据BufferedReader/Writer易处理行数据需要类型转换
结构化二进制数据DataInput/OutputStream高效,类型安全二进制不可读
复杂对象持久化ObjectInput/OutputStream直接序列化对象版本兼容问题
高性能大文件处理NIO Channel + Buffer零拷贝,内存映射编程复杂

八、最佳实践总结

  1. 始终包装缓冲流

    // 正确用法
    new DataInputStream(new BufferedInputStream(new FileInputStream("data.bin"))
    );
  2. 处理版本兼容

    // 文件头写入版本号
    dos.writeInt(2); // 版本2
  3. 重要数据添加校验

    // 写入CRC32校验
    dos.writeInt(data.length);
    dos.write(data);
    dos.writeLong(crc32.getValue());
  4. 处理字节顺序

    // 明确字节序
    if (dis.readByte() == 0x01) {// 小端序数据// 需要特殊处理
    }
  5. 关闭资源安全

    try (DataOutputStream dos = ...) {// 自动关闭所有包装流
    }

DataInputStreamDataOutputStream 提供了在 Java 中处理原始数据类型的高效方式,特别适合存储结构化数据、游戏存档、科学数据记录等场景。掌握它们的使用能显著提升二进制数据处理效率!

http://www.dtcms.com/a/301258.html

相关文章:

  • 《中国棒球》cba外援规则·棒球1号位
  • Java排序中(a).compareTo(b)与Integer.compare(a, b)区别
  • Java学习-------外观模式
  • incus套件在 主力 Linux Distros 上的安装配置与基本使用
  • 【NLP实践】三、LLM搭建中文知识库:提供RestfulAPI服务
  • LeetCode第349题_两个数组的交集
  • python 阿里云 安装 dashscope的简介、安装
  • c语言结构体字节对齐
  • github上传本地项目过程记录
  • Spring经典“送命题”:BeanFactory vs FactoryBean
  • Flutter中实现页面跳转功能
  • vulhub-red靶机攻略
  • 深度学习计算(深度学习-李沐-学习笔记)
  • IKAnalyzer分词插件使用方法
  • 第十八章:AI的“通感”:揭秘图、文、音的共同语言——CLIP模型
  • 图像智能识别(一)-Python方向
  • 嵌入式学习日志————对射式红外传感器计次
  • 「iOS」————ARC
  • MyBatis-Plus 条件构造器(Wrapper)全解析
  • docker in docker - 在docker容器中使用宿主机的docker
  • mac电脑安装docker图文教程
  • Java面试全栈通关:从微服务到AI的技术深度解析
  • [10月考试] C
  • Java面试全攻略:Spring生态与微服务架构实战
  • LangChain实现RAG
  • [2025CVPR-图象超分辨方向]DORNet:面向退化的正则化网络,用于盲深度超分辨率
  • 马尔可夫链
  • 设计模式(十三)结构型:代理模式详解
  • Python 使用 asyncio 包处理并 发(避免阻塞型调用)
  • 图像智能识别算法记录