什么是字节流?
字节流是Java I/O中最基本的流,以字节(byte)为单位进行数据读写。所有数据本质上都是二进制字节,所以字节流可以处理任何类型的数据——图片、音频、视频、可执行文件等。
生活比喻
字节流就像水管,只能传输水(字节)。无论你传输的是纯净水(文本)还是汤(图片/视频),都只能以水分子(字节)的形式通过。字符流则像是专门设计的饮料管,有不同的处理方式来保持饮料的特性。
字节流家族体系
InputStream(输入字节流)
│
├── FileInputStream ← 文件输入流
├── BufferedInputStream ← 带缓冲,提高效率
├── ByteArrayInputStream ← 字节数组输入
├── ObjectInputStream ← 对象输入流(反序列化)
└── FilterInputStream ← 装饰器基类
OutputStream(输出字节流)
│
├── FileOutputStream ← 文件输出流
├── BufferedOutputStream ← 带缓冲
├── ByteArrayOutputStream ← 字节数组输出
└── ObjectOutputStream ← 对象输出流(序列化)
FileInputStream - 读取文件
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) {
String path = "test.txt";
// 方法1:一个字节一个字节读(效率低)
System.out.println("===== 单字节读取 =====");
try (FileInputStream fis = new FileInputStream(path)) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
// 方法2:批量读取到字节数组(效率高)
System.out.println("\n\n===== 批量读取 =====");
try (FileInputStream fis = new FileInputStream(path)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
String content = new String(buffer, 0, bytesRead);
System.out.print(content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileOutputStream - 写入文件
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) {
String path = "output.txt";
// 写入字符串
System.out.println("===== 写入文件 =====");
try (FileOutputStream fos = new FileOutputStream(path)) {
String text = "Hello, Java IO!\n这是第二行。";
fos.write(text.getBytes()); // 将字符串转为字节数组写入
System.out.println("写入成功!");
} catch (IOException e) {
e.printStackTrace();
}
// 追加模式写入
System.out.println("===== 追加写入 =====");
try (FileOutputStream fos = new FileOutputStream(path, true)) {
String append = "\n这是追加的内容。";
fos.write(append.getBytes());
System.out.println("追加成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
BufferedInputStream/BufferedOutputStream - 缓冲流
缓冲流是装饰器模式的应用,它在内部维护一个缓冲区,减少实际的I/O操作次数,显著提高性能。
import java.io.*;
public class BufferedStreamDemo {
public static void main(String[] args) {
String source = "source.txt";
String dest = "dest.txt";
// 使用缓冲流复制文件
System.out.println("===== 缓冲流文件复制 =====");
long start = System.currentTimeMillis();
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);
}
System.out.println("复制完成!");
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("耗时: " + (end - start) + "ms");
}
}
为什么需要缓冲流?
| 对比项 | 无缓冲 | 有缓冲 |
|---|---|---|
| 每次read() | 调用一次系统read() | 从内存缓冲区读取 |
| 磁盘访问 | 每次读写都访问 | 缓冲区满才访问 |
| 性能 | 低 | 高 |
| 适用场景 | 小文件、随机访问 | 大文件、顺序读写 |
文件复制完整示例
import java.io.*;
public class FileCopyDemo {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("用法: java FileCopy <源文件> <目标文件>");
return;
}
String source = args[0];
String dest = args[1];
System.out.println("源文件: " + source);
System.out.println("目标文件: " + dest);
long startTime = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(source));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(dest))
) {
byte[] buffer = new byte[4096];
int bytesRead;
long totalBytes = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
long endTime = System.currentTimeMillis();
System.out.println("复制完成!");
System.out.println("文件大小: " + totalBytes + " 字节");
System.out.println("耗时: " + (endTime - startTime) + " ms");
} catch (FileNotFoundException e) {
System.out.println("文件不存在: " + e.getMessage());
} catch (IOException e) {
System.out.println("I/O错误: " + e.getMessage());
}
}
}
ByteArrayInputStream/ByteArrayOutputStream
字节数组流用于在内存中进行I/O操作,不需要关闭。
import java.io.*;
public class ByteArrayStreamDemo {
public static void main(String[] args) {
// 写入字节数组
System.out.println("===== 字节数组输出 =====");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String text = "Hello, ByteArrayStream!";
baos.write(text.getBytes());
byte[] data = baos.toByteArray();
System.out.println("写入的字节数组: " + new String(data));
// 从字节数组读取
System.out.println("\n===== 字节数组输入 =====");
ByteArrayInputStream bais = new ByteArrayInputStream(data);
int b;
while ((b = bais.read()) != -1) {
System.out.print((char) b);
}
System.out.println();
}
}
小结
- 字节流以字节为单位处理所有二进制数据
- InputStream是输入字节流的抽象基类
- OutputStream是输出字节流的抽象基类
- FileInputStream/FileOutputStream用于文件读写
- Bufferedxxx缓冲流提高I/O效率,应优先使用
- 使用try-with-resources确保流正确关闭