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体系的基础组件,定义了字节输出流的标准接口,通过抽象方法和模板模式为子类提供了统一的操作框架。
理解其设计思想和源码实现,有助于高效使用各种具体流类,并在需要时自定义扩展。
