OutputStream
852字约3分钟
2024-08-08
和 InputStream
类似,OutputStream
也是抽象类,它是所有输出流的超类。这个抽象类定义的一个最重要的方法就是 void write(int b)
,签名如下
public abstract void write(int b) throws IOException;
这个方法会写入一个字节到输出流。要注意的是,虽然传入的是 int
参数,但只会写入一个字节,即只写入 int
最低 8
位表示字节的部分
和 InputStream
类似,OutputStream
也提供了 close()
方法关闭输出流,以便释放系统资源。要特别注意:OutputStream
还提供了一个 flush()
方法,它的目的是将缓冲区的内容真正输出到目的地
flush()
为什么要有 flush()
?因为向磁盘、网络写入数据的时候,出于效率的考虑,操作系统并不是输出一个字节就立刻写入到文件或者发送到网络,而是把输出的字节先放到内存的一个缓冲区里(本质上就是一个 byte[]
数组),等到缓冲区写满了,再一次性写入文件或者网络。对于很多 IO
设备来说,一次写一个字节和一次写 1000
个字节,花费的时间几乎是完全一样的,所以 OutputStream
有个 flush()
方法,能强制把缓冲区内容输出
通常情况下,我们不需要调用这个 flush()
方法,因为缓冲区写满了 OutputStream
会自动调用它,并且,在调用 close()
方法关闭 OutputStream
之前,也会自动调用 flush()
方法
某些情况下,我们必须手动调用 flush()
方法。举个栗子
小明正在开发一款在线聊天软件,当用户输入一句话后,就通过 OutputStream的write()
方法写入网络流。小明测试的时候发现,发送方输入后,接收方根本收不到任何信息,怎么肥四?
原因就在于写入网络流是先写入内存缓冲区,等缓冲区满了才会一次性发送到网络。如果缓冲区大小是 4K
,则发送方要敲几千个字符后,操作系统才会把缓冲区的内容发送出去,这个时候,接收方会一次性收到大量消息
解决办法就是每输入一句话后,立刻调用 flush()
,不管当前缓冲区是否已满,强迫操作系统把缓冲区的内容立刻发送出去
FileOutputStream
我们以 FileOutputStream
为例,演示如何将若干个字节写入文件流
public void writeFile() throws IOException {
try (OutputStream output = new FileOutputStream("D:\\marui\b.txt")) {
output.write(72); // H
output.write(101); // e
output.write(108); // l
output.write(108); // l
output.write(111); // o
} // 编译器在此自动为我们写入finally并调用close()
}
每次写入一个字节非常麻烦,更常见的方法是一次性写入若干字节。可以用 OutputStream
提供的重载方法 void write(byte[])
来实现
public void writeFile() throws IOException {
try (OutputStream output = new FileOutputStream("D:\\marui\b.txt")) {
output.write("Hello".getBytes("UTF-8")); // Hello
}
}
阻塞
和 InputStream
一样,OutputStream
的 write()
方法也是阻塞的
OutputStream 实现类
用 FileOutputStream
可以从文件获取输出流,这是 OutputStream
常用的一个实现类。此外,ByteArrayOutputStream
可以在内存中模拟一个 OutputStream
public static void main(String[] args) throws IOException {
byte[] data;
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
output.write("Hello ".getBytes("UTF-8"));
output.write("world!".getBytes("UTF-8"));
data = output.toByteArray();
}
System.out.println(new String(data, "UTF-8"));
}