Java OutputStream 类(java.io.OutputStream)是 Java IO API 中所有输出流的基类。OutputStream 的子类包括 Java BufferedOutputStream 和 Java FileOutputStream 等。要查看输出流的完整列表,请访问 Java IO 概述页面底部的表格。
以下是 Java OutputStream 类的一些著名子类:
ByteArrayOutputStream
FileOutputStream
PipedOutputStream
BufferedOutputStream
FilterOutputStream
DataOutputStream
PrintStream
ObjectOutputStream
如 Java IO 概述所述,Java OutputStream 通常连接到某个数据目标,如文件、网络连接、管道、内存缓冲区等。Java IO 概述中对此也有更详细的解释。OutputStream 的数据目标是所有写入 OutputStream 的数据最终结束的地方。
write(byte) 方法用于将单个字节写入 Java OutputStream。OutputStream 的 write() 方法接收一个 int,其中包含要写入的字节的字节值。只有 int 值的第一个字节会被写入。其余部分将被忽略。
OutputStream 的子类可能有其他 write() 方法。例如,DataOutputStream 允许使用相应的 writeBoolean() 和 writeDouble() 方法写入 int、long、float、double、boolean 等 Java 基元数据。
下面是一个 OutputStream write() 示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); while(hasMoreData()) { int data = getMoreData(); outputStream.write(data); } outputStream.close();
这个 OutputStream write() 示例首先创建了一个 FileOutputStream,并将数据写入其中。然后,示例进入 while 循环。退出 while 循环的条件是方法 hasMoreData() 的返回值。hasMoreData() 的实现没有显示,但可以想象,如果有更多数据要写入,它将返回 true;如果没有,则返回 false。
在 while 循环中,示例调用 getMoreData() 方法获取下一个要写入 OutputStream 的数据,然后将该数据写入 OutputStream。while 循环一直持续到 hasMoreData() 返回 false 为止。
注:为清晰起见,此处略去了正确的异常处理。要了解有关正确异常处理的更多信息,请访问 Java IO 异常处理。
Java OutputStream 的写入方法可让你一次向 OutputStream 写入一个字节数组。这些写入方法是:
write(byte[] bytes)
write(byte[] bytes, int offset, int length)
write(byte[] bytes) 方法将字节数组中的所有字节写入 OutputStream。
write(byte[] bytes, int offset, int length) 方法将从字节数组的索引偏移量开始的长度字节写入 OutputStream。
这两种方法都会返回写入 OutputStream 的实际字节数,如果不是整个数组,也可以按要求写入长度字节。
下面是使用这两种写入方法中的第二种将字节数组写入 Java OutputStream 的示例:
OutputStream outputStream = new FileOutputStream("D:\\output.txt"); byte[] sourceBytes = ... // 从某处获取源字节 int bytesWritten = outputStream.write(sourceBytes, 0, sourceBytes.length);
此示例将指示 OutputStream 尝试将 sourceBytes 数组中的所有字节写入 OutputStream。执行此代码后,bytesWritten 变量将包含实际写入 OutputStream 的字节数。
将字节数组写入 Java OutputStream 比一次写入一个字节更快。速度的提升可能非常明显,最高可达 10 倍或更多。因此,建议尽可能使用 write(byte[]) 方法。
具体的速度提升取决于运行 Java 代码的计算机的底层操作系统和硬件。速度提升取决于内存速度、硬盘速度和缓冲区大小、网卡速度和缓冲区大小等问题,具体取决于 OutputStream 将数据发送到哪个目的地。
通过用 Java BufferedOutputStream 对写入 Java OutputStream 的字节进行封装,可以实现透明缓冲。写入 BufferedOutputStream 的所有字节都将首先被缓冲到 BufferedOutputStream 的内部字节数组中。缓冲区满后,缓冲区会被一次性刷新到底层的 OutputStream 中。下面是一个用 BufferedOutputStream 封装 Java OutputStream 的示例:
int bufferSize = 8 * 1024; OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-file.txt"), bufferSize);
有关 BufferedOutputStream 的更多信息,请参阅我的 BufferedOutputStream 教程。
Java OutputStream 的 flush() 方法会将写入 OutputStream 的所有数据刷新到底层数据目标。例如,如果 OutputStream 是 FileOutputStream,那么写入 FileOutputStream 的字节可能尚未完全写入磁盘。即使你的 Java 代码已将数据写入 FileOutputStream,数据也可能在操作系统内存的某个地方缓冲。通过调用 flush(),你可以确保任何缓冲数据都将被刷新(写入)到磁盘(或网络,或 OutputStream 的其他目标)。下面是一个通过调用 flush() 方法刷新写入 Java OutputStream 的数据的示例:
outputStream.flush();
一旦完成向 Java OutputStream 写入数据,就应该关闭它。关闭 OutputStream 的方法是调用其 close() 方法。下面是一个关闭 Java OutputStream 的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); while(hasMoreData()) { int data = getMoreData(); outputStream.write(data); } outputStream.close();
这里省略了 hasMoreData() 和 getMoreData() 的具体实现,但它们对于理解本示例的原理其实并不十分重要。重要的是,一旦 while 循环结束,向 OutputStream 写入数据的过程结束,就会调用 close() 方法关闭 OutputStream。
不过,上述示例并不完全可靠。如果 write() 方法抛出异常,close() 方法将永远不会被调用。异常将使程序退出上述代码所在的任何方法。
相反,你应该使用 Java try with resources 结构来关闭 OutputStream。下面是一个使用 try with-resources 结构关闭 Java OutputStream 的示例:
try( OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt")) { while(hasMoreData()) { int data = getMoreData(); outputStream.write(data); } }
一旦退出 try 代码块,就会自动调用 OutputStream 的 close() 方法,因为 OutputStream 是在 try 代码块的括号内声明的。即使在 try 代码块内部出现异常,也会在异常向调用堆栈传播之前调用 close() 方法。
Java OutputStream 是基于字节的流。你可以使用 Java OutputStreamWriter 类将 OutputStream 转换为基于字符的 Writer。下面是一个使用 OutputStreamWriter 将 Java OutputStream 转换为 Writer 的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output.txt"); Writer outputStreamWriter = new OutputStreamWriter(outputStream); outputStreamWriter.write("Hello World");
你可以在我的 OutputStreamWriter 教程中阅读更多有关如何使用 OutputStreamWriter 的信息,包括如何设置将字符转换为字节时使用的字符编码。