Java中FileWriter和BufferedWriter的区别

81

它们之间有什么区别?我现在正在学习Java,但似乎我可以两种方式写入文件。

FileWriter file = new FileWriter("foo.txt");
file.write("foobar");
file.close();

FileWriter file = new FileWriter("foo.txt");
BufferedWriter bf = new BufferedWriter(file);
bf.write("foobar");
bf.close();

我理解先缓冲数据的概念,那么这是否意味着第一个示例逐个写入字符,而第二个示例首先将其缓冲到内存中然后一次性写入?

6个回答

92

如果你在flush/close之间进行多次写操作,且这些写操作相对于缓冲区大小来说较小,那么使用BufferedWriter更有效率。

在你的例子中,只有一次写操作,因此使用BufferedWriter会增加不必要的开销。

这是否意味着第一个示例逐个字符地写入,而第二个示例首先将其缓冲到内存中,然后一次性写入?

在两种情况下,字符串都是一次性写入的。

如果你仅使用FileWriter进行write(String)调用,则:

 public void write(String str, int off, int len) 
        // some code
        str.getChars(off, (off + len), cbuf, 0);
        write(cbuf, 0, len);
 }

每次 write(String) 调用都会进行一次系统调用。


BufferedWriter 在多次小写操作时提高了效率。

for(int i = 0; i < 100; i++) {
    writer.write("foorbar");
    writer.write(NEW_LINE);
}
writer.close();

如果没有BufferedWriter,这可能会导致200次(2 * 100)系统调用和写入磁盘,效率低下。有了BufferedWriter,所有这些动作都可以一起缓冲,因为默认缓冲区大小为8192个字符,因此只需要1个系统调用来完成写操作。


我有一个问题,就是当我使用 FileWriter 时,在 write 返回之后,Java 是否保证内容已经刷新到磁盘上了,或者仅仅在页面缓存中等待操作系统需要时刷新? - JaskeyLam
@Jaskey 如果你使用未缓冲的FileWriter,write() 意味着操作系统有一个副本,最终应该写入磁盘。 - Peter Lawrey
2
也许在10年前是这样,但至少在Java 11中,FileWriter扩展了OutputStreamWriter,后者使用StreamEncoder,后者又有自己的内部8KB缓冲区(出于不同的原因而不是BufferedWriter,但它仍然是一个缓冲区)。因此,您可能不会像调用write()一样多次写入磁盘。 - Gustavo

8
你说得对。这是 BufferedWriterwrite() 方法的样子:
public void write(int c) throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (nextChar >= nChars)
            flushBuffer();
        cb[nextChar++] = (char) c;
    }
}

正如您所看到的,它确实检查缓冲区是否已满(if (nextChar >= nChars))并刷新缓冲区。然后将新字符添加到缓冲区(cb[nextChar++] = (char) c;)。


5

BufferedWriter更有效率。如果我没记错的话,它会保存小写入,并一次性写入大块数据。如果你正在进行大量的小写入操作,那么我建议使用BufferedWriter。调用写入操作会调用操作系统,这很慢,因此尽可能减少写入次数通常是可取的。


0

在未缓冲的输入/输出(FileWriter,FileReader)中,读取或写入请求直接由底层操作系统处理。https://hajsoftutorial.com/java/wp-content/uploads/2018/04/Unbuffered.gif

这可能会使程序效率大大降低,因为每个此类请求通常会触发磁盘访问、网络活动或其他相对昂贵的操作。为了减少这种开销,Java平台实现了缓冲I/O流。BufferedReader和BufferedWriter类提供内部字符缓冲区。写入缓冲区的文本存储在内部缓冲区中,并且仅在缓冲区填满或刷新时才写入底层写入器。 https://hajsoftutorial.com/java/wp-content/uploads/2018/04/bufferedoutput.gif

更多信息请参见https://hajsoftutorial.com/java-bufferedwriter/


0

来自Java API规范:

FileWriter

用于写入字符文件的便捷类。该类的构造函数假定默认字符编码和默认字节缓冲区大小是可接受的。

BufferedWriter

将文本写入字符输出流,缓冲字符以提供单个字符、数组和字符串的高效写入。


0

http://docs.oracle.com/javase/1.5.0/docs/api/java/io/BufferedWriter.html

一般来说,Writer 立即将其输出发送到底层字符或字节流。除非需要及时输出,否则建议对任何可能具有昂贵 write() 操作的 Writer 进行包装,例如 FileWriters 和 OutputStreamWriters,使用 BufferedWriter。例如,
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲 PrintWriter 的输出到文件中。如果没有缓冲,则每次调用 print() 方法都会导致字符被转换为字节,然后立即写入文件,这可能非常低效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接