跳转到主内容
思享编程网:思考分享,玩转编程世界!

Java IO `OutputStream` 详解及源码解析

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体系的基础组件,定义了字节输出流的标准接口,通过抽象方法和模板模式为子类提供了统一的操作框架。

理解其设计思想和源码实现,有助于高效使用各种具体流类,并在需要时自定义扩展。

相关文章