Java FileOutputStream 类(java.io.FileOutputStream)可将文件写成字节流。Java FileOutputStream 类是 Java OutputStream 的子类,这意味着你可以将 FileOutputStream 用作 OutputStream。
以下是一个简单的 Java FileOutputStream 示例::
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt"); while(moreData) { int data = getMoreData(); output.write(data); } output.close();
注:为清晰起见,此处略去了正确的异常处理。要了解有关正确异常处理的更多信息,请访问 Java IO 异常处理。本教程底部关于关闭 Java FileOutputStream 的部分也有一个更好的异常处理示例。
Java FileOutputStream 类包含一组不同的有用构造函数。我将在此介绍最常用的构造函数。
第一个构造函数接收一个字符串,其中包含要写入文件的路径。下面是一个示例:
String path = "C:\\data\\datafile.txt"; FileOutputStream output = new FileOutputStream(path);
请注意路径字符串。它需要双反斜线(\\)才能在字符串中创建单反斜线,因为反斜线是 Java 字符串中的转义字符。要获得单反斜线,需要使用转义序列 (\\)。
在 unix 上,文件路径可能是这样的:
String path = "/home/hxstrive/data/datafile.txt";
第二个 FileOutputStream 构造函数接收一个 Java File 对象,该对象指向文件系统中的文件。下面是一个示例:
String path = "C:\\data\\datafile.txt"; File file = new File(path); FileOutputStream output = new FileOutputStream(file);
创建指向已存在文件的 Java FileOutputStream 时,你可以决定是要覆盖现有文件,还是要追加到现有文件。这取决于你选择使用哪个 FileOutputStream 构造函数。
该构造函数只有一个参数,即文件名,它将覆盖任何现有文件:
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt");
有一个构造函数也需要 2 个参数: 文件名和一个布尔值。布尔值表示是否追加文件。因此,值为 true 表示要追加到文件,而值为 false 表示要覆盖文件。下面是两个 Java FileOutputStream 构造函数示例:
OutputStream output = new FileOutputStream("c:\\data\\output-text.txt", true); //append OutputStream output = new FileOutputStream("c:\\data\\output-text.txt", false); //overwrite
如果不使用第二个布尔参数,只使用接收文件路径的构造函数,默认模式是覆盖指定路径上的任何现有文件。
要向 Java FileOutputStream 写入数据,可以使用其 write() 方法。write() 方法接收一个 int,其中包含要写入的字节的字节值。因此,只有传入的 int 的低 8 位才会实际写入 FileOutputStream 目标地址。下面是一个使用 write() 方法将数据写入 Java FileOutputStream 的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); outputStream.write(123);
此示例将字节值 123 写入给定的 Java FileOutputStream。
由于 Java FileOutputStream 是 OutputStream 的子类,因此你也可以向 FileOutputStream 写入字节数组,而不是一次只写一个字节。下面是一个将字节数组写入 Java FileOutputStream 的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); byte bytes = new byte[]{1,2,3,4,5}; outputStream.write(bytes);
将字节数组写入 Java FileOutputStream 比一次写入一个字节更快。速度的提升可能非常明显,最高可达 10 倍或更多。因此,建议尽可能使用 write(byte[]) 方法。
具体的速度提升取决于运行 Java 代码的计算机的底层操作系统和硬件。速度提升取决于内存速度、硬盘速度和缓冲区大小等问题。
通过用 Java BufferedOutputStream 对写入 Java FileOutputStream 的字节进行封装,可以实现透明缓冲。写入 FileOutputStream 的所有字节都将首先被缓冲到 BufferedOutputStream 的内部字节数组中。当缓冲区满时,缓冲区会被一次性刷新到磁盘。下面是一个用 BufferedOutputStream 封装 Java FileOutputStream 的示例:
int bufferSize = 8 * 1024; FileOutputStream output = new BufferedOutputStream( new FileOutputStream("c:\\data\\output-file.txt"), bufferSize );
有关 BufferedOutputStream 的更多信息,请参阅我的 BufferedOutputStream 教程。
当你向 Java FileOutputStream 写入数据时,数据可能会缓存在计算机内存中,并在稍后写入磁盘。例如,每次有 X 量的数据要写入时,或 FileOutputStream 关闭时。
如果想确保所有写入的数据都写入磁盘,而无需关闭 FileOutputStream,可以调用它的 flush() 方法。调用 flush() 将确保迄今为止写入 FileOutputStream 的所有数据也全部写入磁盘。下面是一个调用 Java FileOutputStream flush() 方法的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); byte bytes = new byte[]{1,2,3,4,5}; outputStream.write(bytes); outputStream.flush()
与其他 OutputStream 一样,FileOutputStream 实例在使用后需要关闭。为此,你可以调用它的 close() 方法。下面是一个通过调用 close() 方法关闭 Java FileOutputStream 的示例:
OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt"); outputStream.write(123); outputStream.close();
遗憾的是,如果在上例中调用 write() 时出现异常,那么异常将导致程序流程在调用 close() 方法之前中断。因此,最好使用 Java try with resources 结构来关闭 Java FileOutputStream。下面是一个使用 try-with-resources 结构关闭 Java FileOutputStream 的示例:
try( OutputStream outputStream = new FileOutputStream("c:\\data\\output-text.txt") ) { outputStream.write(123); }
注意文件输出流(FileOutputStream)是如何在 try 关键字后面的括号内声明的。一旦程序流程退出 try 代码块,无论是否抛出异常,在这些括号内声明的所有资源都将自动关闭。换句话说,FileOutputStream close() 会被自动调用。
Java FileOutputStream 是基于字节的流。你可以使用 Java OutputStreamWriter 类将 FileOutputStream 转换为基于字符的 Writer。下面是一个使用 OutputStreamWriter 将 Java FileOutputStream 转换为 Writer 的示例:
FileOutputStream outputStream = new FileOutputStream("c:\\data\\output.txt"); Writer outputStreamWriter = new OutputStreamWriter(outputStream); outputStreamWriter.write("Hello World");
你可以在我的 OutputStreamWriter 教程中阅读更多有关如何使用 OutputStreamWriter 的信息,包括如何设置将字符转换为字节时使用的字符编码。