1962 字
约 6 分钟
11
第58章 Java字节流
2026-09-24
无标签
第58章 Java字节流
面包屑导航 章节标题 学习目标
学习目标
- 理解字节流的概念和特点
- 掌握InputStream和OutputStream的基本使用方法
- 学会使用FileInputStream和FileOutputStream进行文件操作
- 理解缓冲流BufferedInputStream和BufferedOutputStream的优势
- 掌握数据流DataInputStream和DataOutputStream的使用
- 学会使用字节数组流ByteArrayInputStream和ByteArrayOutputStream
- 了解字节流的最佳实践和性能优化
字节流概述
字节流概述
字节流是Java I/O系统的基础,用于处理二进制数据。所有的字节流都继承自InputStream和OutputStream抽象类。
字节流的特点:处理二进制数据:适合处理图片、音频、视频等二进制文件以字节为单位:每次读写一个或多个字节通用性强:可以处理任何类型的文件效率较高:直接操作字节,没有编码转换开销
主要字节流类型
主要字节流类型
基础字节流
- FileInputStream / FileOutputStream
- 直接操作文件
- 适合小文件操作
- 需要手动关闭资源
缓冲字节流
- BufferedInputStream / BufferedOutputStream
- 内置缓冲区,减少系统调用
- 显著提高I/O性能
- 适合大文件操作
数据字节流
- DataInputStream / DataOutputStream
- 可以直接读写Java基本数据类型
- 保持数据类型的完整性
- 适合结构化数据存储
字节数组流
- ByteArrayInputStream / ByteArrayOutputStream
- 在内存中操作,不涉及磁盘I/O
- 速度快,适合临时数据处理
- 支持动态扩容
基础字节流示例
基础字节流示例
FileInputStream 和 FileOutputStream
import java.io.*;
public class ByteStreamBasics {
// 演示FileInputStream读取文件
public static void demonstrateFileInputStream(String fileName) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
// 逐字节读取
int byteData;
while ((byteData = fis.read()) != -1) {
System.out.print((char)byteData);
}
} catch (IOException e) {
System.err.println("读取文件时发生错误: " + e.getMessage());
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
System.err.println("关闭流时发生错误: " + e.getMessage());
}
}
}
}
// 演示FileOutputStream写入文件
public static void demonstrateFileOutputStream(String fileName, String content) {
try (FileOutputStream fos = new FileOutputStream(fileName)) {
// 将字符串转换为字节数组并写入
byte[] bytes = content.getBytes();
fos.write(bytes);
System.out.println("成功写入文件: " + fileName);
} catch (IOException e) {
System.err.println("写入文件时发生错误: " + e.getMessage());
}
}
}
💻 查看完整代码 - 在线IDE体验 缓冲字节流
缓冲字节流
缓冲流通过内置缓冲区来减少系统调用次数,显著提高I/O性能。
// 使用普通流复制文件
private static void copyFileWithNormalStream(String sourceFile, String targetFile) {
try (FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = new FileOutputStream(targetFile)) {
int byteData;
while ((byteData = fis.read()) != -1) {
fos.write(byteData);
}
} catch (IOException e) {
System.err.println("普通流复制文件失败: " + e.getMessage());
}
}
// 使用缓冲流复制文件
private static void copyFileWithBufferedStream(String sourceFile, String targetFile) {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {
int byteData;
while ((byteData = bis.read()) != -1) {
bos.write(byteData);
}
} catch (IOException e) {
System.err.println("缓冲流复制文件失败: " + e.getMessage());
}
}
**性能提升:**对于大文件操作,缓冲流通常比普通流快3-10倍,因为它减少了系统调用的次数。
数据字节流
数据字节流
数据流可以直接读写Java基本数据类型,保持数据的完整性和类型信息。
// 写入不同类型的数据
public static void demonstrateDataOutput(String fileName) {
try (DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)))) {
// 写入不同类型的数据
dos.writeBoolean(true);
dos.writeByte(127);
dos.writeShort(32767);
dos.writeInt(2147483647);
dos.writeLong(9223372036854775807L);
dos.writeFloat(3.14159f);
dos.writeDouble(2.718281828459045);
dos.writeUTF("Hello, DataStream!");
System.out.println("数据写入完成");
} catch (IOException e) {
System.err.println("写入数据时发生错误: " + e.getMessage());
}
}
// 按写入顺序读取数据
public static void demonstrateDataInput(String fileName) {
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(new FileInputStream(fileName)))) {
boolean boolValue = dis.readBoolean();
byte byteValue = dis.readByte();
short shortValue = dis.readShort();
int intValue = dis.readInt();
long longValue = dis.readLong();
float floatValue = dis.readFloat();
double doubleValue = dis.readDouble();
String stringValue = dis.readUTF();
// 输出读取的数据
System.out.println("boolean: " + boolValue);
System.out.println("byte: " + byteValue);
System.out.println("short: " + shortValue);
System.out.println("int: " + intValue);
System.out.println("long: " + longValue);
System.out.println("float: " + floatValue);
System.out.println("double: " + doubleValue);
System.out.println("String: " + stringValue);
} catch (IOException e) {
System.err.println("读取数据时发生错误: " + e.getMessage());
}
}
字节数组流
字节数组流
字节数组流在内存中操作,不涉及磁盘I/O,适合临时数据处理和数据转换。
// 演示ByteArrayOutputStream的使用
public static void demonstrateByteArrayOutput() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// 写入字符串数据
String text1 = "Hello, ";
String text2 = "ByteArrayStream!";
baos.write(text1.getBytes());
baos.write(text2.getBytes());
// 获取字节数组
byte[] data = baos.toByteArray();
System.out.println("写入的数据: " + new String(data));
System.out.println("字节数组长度: " + data.length);
System.out.println("流的大小: " + baos.size());
// 重置流
baos.reset();
System.out.println("重置后流的大小: " + baos.size());
} catch (IOException e) {
System.err.println("操作ByteArrayOutputStream时发生错误: " + e.getMessage());
} finally {
try {
baos.close();
} catch (IOException e) {
System.err.println("关闭流时发生错误: " + e.getMessage());
}
}
}
// 演示ByteArrayInputStream的使用
public static void demonstrateByteArrayInput() {
String originalText = "Java字节数组流示例";
byte[] data = originalText.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
try {
System.out.println("原始数据: " + originalText);
System.out.println("可用字节数: " + bais.available());
// 批量读取
byte[] buffer = new byte[1024];
int bytesRead = bais.read(buffer);
if (bytesRead != -1) {
String readText = new String(buffer, 0, bytesRead);
System.out.println("读取的内容: " + readText);
}
} catch (IOException e) {
System.err.println("操作ByteArrayInputStream时发生错误: " + e.getMessage());
} finally {
try {
bais.close();
} catch (IOException e) {
System.err.println("关闭流时发生错误: " + e.getMessage());
}
}
}
字节流比较
字节流类型比较
| 流类型 | 适用场景 | 性能特点 | 使用建议 |
|---|---|---|---|
| FileInputStream/FileOutputStream | 小文件读写、简单文件操作 | 直接操作,无缓冲 | 适合小文件或一次性操作 |
| BufferedInputStream/BufferedOutputStream | 大文件读写、频繁I/O操作 | 高性能,减少系统调用 | 推荐用于大文件操作 |
| DataInputStream/DataOutputStream | 结构化数据存储、基本类型读写 | 类型安全,数据完整 | 适合配置文件、数据交换 |
| ByteArrayInputStream/ByteArrayOutputStream | 内存数据处理、临时存储 | 内存操作,速度最快 | 适合数据转换、临时缓存 |
最佳实践
字节流最佳实践
编程建议
推荐做法
- 使用try-with-resources自动管理资源,确保流被正确关闭
- 使用缓冲流提高性能对于大文件操作,使用BufferedInputStream/BufferedOutputStream
- 批量读写数据使用字节数组而不是逐字节操作
- 选择合适的缓冲区大小根据文件大小和内存情况选择合适的缓冲区
避免的做法
- 忘记关闭流可能导致资源泄露和文件锁定
- 逐字节处理大文件效率低下,应使用缓冲区
- 不使用缓冲区对于大文件,直接使用FileInputStream效率较低
- 忽略异常处理I/O操作容易出错,必须妥善处理异常
性能优化建议
性能优化建议
缓冲区大小选择小文件:512字节 - 4KB大文件:8KB - 64KB网络传输:1KB - 8KB
注意事项缓冲区过大会占用更多内存缓冲区过小会增加系统调用次数需要在内存使用和性能之间找到平衡
章节总结
章节总结
- 字节流是Java I/O的基础,适合处理二进制数据
- FileInputStream/FileOutputStream用于基本文件操作
- BufferedInputStream/BufferedOutputStream显著提高大文件操作性能
- DataInputStream/DataOutputStream适合结构化数据存储
- ByteArrayInputStream/ByteArrayOutputStream适合内存数据处理
- 使用try-with-resources确保资源正确释放
- 选择合适的流类型和缓冲区大小可以优化性能
导航链接 上一章:Java IO概述 章节测试 下一章:Java字符流 JavaScript
评论
0 条
还没有评论,先写一条吧。