本文目录导读:

字节流是 Java I/O 的核心概念之一,主要用于处理二进制数据(如图片、音频、视频、压缩文件等),下面通过几个典型案例来详细说明如何使用字节流。
基本概念回顾
字节流的顶层抽象类:
- InputStream:字节输入流
- OutputStream:字节输出流
常用实现类:
FileInputStream/FileOutputStream:文件字节流BufferedInputStream/BufferedOutputStream:缓冲字节流DataInputStream/DataOutputStream:数据字节流ObjectInputStream/ObjectOutputStream:对象字节流
案例一:文件复制(基础操作)
这个案例展示了字节流最基本的读写操作。
import java.io.*;
public class FileCopyExample {
public static void main(String[] args) {
// 源文件和目标文件路径
String sourceFile = "source.jpg";
String destFile = "dest.jpg";
try (FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = new FileOutputStream(destFile)) {
// 方式1:逐字节读取(效率低,不推荐)
// int byteData;
// while ((byteData = fis.read()) != -1) {
// fos.write(byteData);
// }
// 方式2:使用缓冲区(推荐)
byte[] buffer = new byte[1024]; // 1KB缓冲区
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead); // 写入实际读取的字节数
}
System.out.println("文件复制成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键点:
- 使用
try-with-resources自动关闭资源 - 使用缓冲区提高效率
read(buffer)返回实际读取的字节数
案例二:图片文件加密/解密
演示如何通过修改字节数据实现简单的加密功能。
import java.io.*;
public class ImageEncryptor {
// 简单的 XOR 加密/解密
private static final byte KEY = 0x5A; // 密钥
public static void encryptFile(String inputPath, String outputPath) throws IOException {
try (FileInputStream fis = new FileInputStream(inputPath);
FileOutputStream fos = new FileOutputStream(outputPath)) {
byte[] buffer = new byte[4096]; // 4KB缓冲区
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
// 对每个字节进行 XOR 操作
for (int i = 0; i < bytesRead; i++) {
buffer[i] ^= KEY;
}
fos.write(buffer, 0, bytesRead);
}
}
}
public static void main(String[] args) {
try {
// 加密图片
encryptFile("original.jpg", "encrypted.jpg");
System.out.println("图片加密成功!");
// 解密图片(同样的操作)
encryptFile("encrypted.jpg", "decrypted.jpg");
System.out.println("图片解密成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
案例三:读取二进制文件并解析
演示如何读取二进制文件格式(如 BMP 图片头信息)。
import java.io.*;
public class BMPHeaderReader {
public static void readBMPHeader(String filePath) throws IOException {
try (FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream bis = new BufferedInputStream(fis)) {
// BMP文件头(共14字节)
byte[] header = new byte[14];
bis.read(header);
// 验证BMP文件标识
if (header[0] != 'B' || header[1] != 'M') {
System.out.println("不是有效的BMP文件");
return;
}
// 读取文件大小(4字节,小端序)
int fileSize = readLittleEndianInt(header, 2);
System.out.println("文件大小: " + fileSize + " 字节");
// 读取位图数据偏移量(4字节)
int dataOffset = readLittleEndianInt(header, 10);
System.out.println("数据偏移量: " + dataOffset + " 字节");
// 读取DIB头(通常40字节)
byte[] dibHeader = new byte[40];
bis.read(dibHeader);
// 读取宽度和高度
int width = readLittleEndianInt(dibHeader, 4);
int height = readLittleEndianInt(dibHeader, 8);
System.out.println("图像尺寸: " + width + " x " + height);
// 读取位深度(2字节)
int bitDepth = readLittleEndianShort(dibHeader, 14);
System.out.println("位深度: " + bitDepth + " bit");
}
}
// 读取小端序的4字节整数
private static int readLittleEndianInt(byte[] data, int offset) {
return (data[offset] & 0xFF) |
((data[offset + 1] & 0xFF) << 8) |
((data[offset + 2] & 0xFF) << 16) |
((data[offset + 3] & 0xFF) << 24);
}
// 读取小端序的2字节整数
private static short readLittleEndianShort(byte[] data, int offset) {
return (short)((data[offset] & 0xFF) | ((data[offset + 1] & 0xFF) << 8));
}
public static void main(String[] args) {
try {
readBMPHeader("image.bmp");
} catch (IOException e) {
e.printStackTrace();
}
}
}
案例四:带缓冲的复制(高性能)
使用 BufferedInputStream 和 BufferedOutputStream 提升性能。
import java.io.*;
public class BufferedCopyExample {
public static void bufferedCopy(String source, String dest) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest))) {
byte[] buffer = new byte[8192]; // 8KB缓冲区
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
// BufferedOutputStream 需要手动 flush
bos.flush();
}
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
try {
bufferedCopy("large_file.mp4", "copy_large_file.mp4");
long endTime = System.currentTimeMillis();
System.out.println("拷贝完成,耗时: " + (endTime - startTime) + "ms");
} catch (IOException e) {
e.printStackTrace();
}
}
}
性能对比与最佳实践
各种方式的性能对比
public class PerformanceComparison {
public static void main(String[] args) throws IOException {
String source = "test.bin";
long startTime, endTime;
// 1. 无缓冲逐字节(最慢)
startTime = System.currentTimeMillis();
copyNoBuffer(source, "copy1.bin");
endTime = System.currentTimeMillis();
System.out.println("无缓冲逐字节: " + (endTime - startTime) + "ms");
// 2. 有缓冲区(较快)
startTime = System.currentTimeMillis();
copyWithBuffer(source, "copy2.bin");
endTime = System.currentTimeMillis();
System.out.println("有缓冲区(1024): " + (endTime - startTime) + "ms");
// 3. 缓冲流(最快)
startTime = System.currentTimeMillis();
copyWithBufferedStream(source, "copy3.bin");
endTime = System.currentTimeMillis();
System.out.println("缓冲流: " + (endTime - startTime) + "ms");
}
private static void copyNoBuffer(String src, String dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
int byteData;
while ((byteData = fis.read()) != -1) {
fos.write(byteData);
}
}
}
private static void copyWithBuffer(String src, String dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
}
}
private static void copyWithBufferedStream(String src, String dest) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest))) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
}
}
}
常见错误处理
public class ErrorHandlingExample {
public void safeFileCopy(String source, String dest) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 检查源文件是否存在
File sourceFile = new File(source);
if (!sourceFile.exists()) {
System.err.println("源文件不存在: " + source);
return;
}
// 检查目标目录是否存在
File destFile = new File(dest);
File parentDir = destFile.getParentFile();
if (parentDir != null && !parentDir.exists()) {
parentDir.mkdirs(); // 创建目录
}
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(destFile);
byte[] buffer = new byte[4096];
int bytesRead;
long totalBytes = 0;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
System.out.println("成功复制 " + totalBytes + " 字节");
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
System.err.println("IO错误: " + e.getMessage());
} finally {
// 确保资源关闭
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
总结与最佳实践
- 使用缓冲区:永远不要逐字节读取,使用
byte[]缓冲区(建议 4KB-8KB) - 使用缓冲流:
BufferedInputStream/BufferedOutputStream能显著提升性能 - 及时关闭资源:使用
try-with-resources自动关闭,或确保在 finally 中关闭 - 选择合适的缓冲区大小:8192 字节(8KB)是一个好的选择
- 注意编码问题:字节流处理二进制数据,字符流处理文本数据,不要混淆
字节流是 Java I/O 的基础,掌握好这些案例和技巧,可以处理绝大多数文件操作场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播