Java的OutputStream是所有字节输出流的抽象基类,位于java.io包中,提供了将字节数据写入目标(如文件、网络连接、内存等)的基本接口。本文将详细解析OutputStream的核心概念、常用方法、设计模式及源码实现。
一、核心概念
1. 作用
OutputStream是Java IO体系中字节输出流的顶层抽象,定义了写入字节数据的标准方法,所有具体的字节输出流类(如FileOutputStream、ByteArrayOutputStream、SocketOutputStream等)都继承自它。
2. 数据目标类型
OutputStream的数据目标可以是:
- 文件(
FileOutputStream) - 内存(
ByteArrayOutputStream) - 网络连接(
Socket.getOutputStream()) - 管道(
PipedOutputStream) - 其他流(如
BufferedOutputStream包装其他流)
二、常用方法
1. 核心写入方法
// 写入单个字节(参数为int,但只写入低8位)
public abstract void write(int b) throws IOException;
// 写入整个字节数组
public void write(byte b[]) throws IOException;
// 写入字节数组b的从off位置开始的len个字节
public void write(byte b[], int off, int len) throws IOException;
2. 其他重要方法
// 刷新缓冲区,确保数据全部写出
public void flush() throws IOException;
// 关闭流,释放资源(关闭前会自动flush)
public void close() throws IOException;
三、源码解析
1. 抽象方法 write(int b)
public abstract void write(int b) throws IOException;
- 作用:写入单个字节数据,参数
b是int类型,但实际只写入其低8位(0-255)。 - 实现要求:所有子类必须实现此方法,它是
OutputStream最核心的方法。
2. 批量写入方法 write(byte[] b)
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
- 作用:将整个字节数组写入输出流,调用了
write(b, 0, b.length)的重载方法。
3. 核心重载方法 write(byte[] b, int off, int len)
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]); // 循环调用抽象方法write(int b)
}
}
- 实现逻辑:
- 检查参数合法性。
- 循环调用
write(int b)方法,逐个写入字节数组中的元素。
- 性能问题:直接使用此方法效率较低,因为每次只写入一个字节,建议使用
BufferedOutputStream包装以提高性能。
4. flush() 方法
public void flush() throws IOException {
// 默认实现为空,因为抽象类无需刷新缓冲区
}
- 作用:确保缓冲区中的数据全部写出到目标。
- 子类重写:如
BufferedOutputStream会在此方法中清空内部缓冲区。
5. close() 方法
public void close() throws IOException {
// 默认实现为空,因为抽象类无需释放资源
}
- 子类重写:如
FileOutputStream会关闭文件句柄,SocketOutputStream会关闭网络连接。通常会先调用flush()确保数据写出。
四、设计模式
1. 模板方法模式
OutputStream定义了核心方法的骨架(如write(byte[])调用write(int b)),具体实现由子类完成,符合模板方法模式。
2. 装饰器模式
FilterOutputStream及其子类(如BufferedOutputStream、DataOutputStream)通过包装其他OutputStream实现功能增强,符合装饰器模式。
五、常见子类
1. FileOutputStream
将数据写入文件,直接关联底层文件描述符。
2. ByteArrayOutputStream
将数据写入内存字节数组,无需进行IO操作,适用于临时数据存储。
3. BufferedOutputStream
通过缓冲区提高写入性能,减少实际IO次数。
4. DataOutputStream
用于写入基本数据类型(如int、double),需配合DataInputStream使用。
5. ObjectOutputStream
用于序列化对象,实现Java对象的持久化。
六、使用示例
1. 写入文件
try (OutputStream os = new FileOutputStream("test.txt")) {
String data = "Hello, World!";
os.write(data.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
2. 使用缓冲流提高性能
try (OutputStream os = new FileOutputStream("test.txt");
BufferedOutputStream bos = new BufferedOutputStream(os)) {
String data = "Hello, World!";
bos.write(data.getBytes());
bos.flush(); // 确保数据全部写出
} catch (IOException e) {
e.printStackTrace();
}
3. 写入基本数据类型
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("data.dat"))) {
dos.writeInt(123);
dos.writeDouble(3.14);
dos.writeUTF("Hello");
} catch (IOException e) {
e.printStackTrace();
}
七、注意事项
- 资源管理:
OutputStream使用完毕后必须调用close()关闭,建议使用try-with-resources语句自动关闭。 - 缓冲区刷新:使用带缓冲的流(如
BufferedOutputStream)时,需调用flush()确保数据写出,close()方法会自动调用flush()。 - 追加模式:
FileOutputStream构造函数可传入append参数(如new FileOutputStream("test.txt", true))以启用追加模式。 - 阻塞特性:传统IO是阻塞的,若需非阻塞IO,可使用
java.nio包中的FileChannel或SocketChannel。
总结
OutputStream作为Java IO体系的基础组件,定义了字节输出流的标准接口,通过抽象方法和模板模式为子类提供了统一的操作框架。理解其设计思想和源码实现,有助于高效使用各种具体流类,并在需要时自定义扩展。
1434

被折叠的 条评论
为什么被折叠?



