【问题标题】:When do PrintWriter automatically print to file?PrintWriter 什么时候自动打印到文件?
【发布时间】:2015-07-31 01:30:22
【问题描述】:

在玩了PrintWriter和文件之后,我有一个疑问,为什么有时我在创建文件时立即读取文件时会出现不一致,例如:

File file = new File("Items.txt");
int loopValue = 10;
try {
    PrintWriter fout = new PrintWriter(file);
    for (int i = 0; i < loopValue; i++) {
        fout.print(i + " asdsadas" + System.lineSeparator());
    }
    //fout.flush(); <-- I know if I call flush or close this problem don't occur
    //fout.close();

    System.out.println("Here is the file:");
    Scanner readFile = new Scanner(file);
    while (readFile.hasNext()) {
        System.out.println(readFile.nextLine());
    }
} catch (FileNotFoundException e) {
    System.err.println(e.getMessage());
}

如果我运行这段代码,我会在控制台中读取一个空文件,如下所示:

Here is the file:

但如果我将loopValue 修改为 10000 之类的值,我会得到这样的结果:

Here is the file:
0 asdsadas
1 asdsadas
2 asdsadas
...
...  continues
...
9356 asdsadas
9357 asdsadas
9358  <--- here ends, note that it doesnt end in the value 9999

我知道如果我在读取文件之前调用flush()close() 可以解决这个问题,但为什么会发生这种情况? PrintWriter 什么时候决定是时候清理它的缓冲区而不告诉它什么时候?为什么当我关闭或刷新PrintWriter 时不会发生这个问题?

谢谢!

【问题讨论】:

  • 请查看下面给出的答案。

标签: java


【解决方案1】:

PrintWriter 缓冲区背后的一般概念和动机是向控制台写入内容的成本很高。因此,通过排队等待输出的更改,程序可以更有效地运行。想象一下,您有一个 Java 程序,从 CPU 的角度来看,它正在做一些非常密集的事情,例如多线程应用程序中的大量计算。然后,如果您坚持每次调用PrintWriter.print() 都立即交付其输出,那么程序可能会挂起,整体性能会下降。

如果您坚持在调用后立即看到来自PrintWriter 的输出,那么您可以调用flush() 来实现此目的。但如前所述,在某些情况下可能会降低性能。

【讨论】:

    【解决方案2】:

    缓冲是加速 I/O 的一项基本且重要的技术

    当您调用close 时,它将释放与其关联的所有系统资源,此处文件将由Printwriter 使用,并且直到您刷新它之前尚未保存您的更改。因此,试图读取文件的Scanner 将获得旧的未更改内容。现在,当您调用flush 时,它只会刷新文件并强制写入器写入所有缓冲的bytes,直到流缓冲您的输入而不是写入到文件。注意这里你应该使用finally块到close流并注意close()默认为你刷新流但是在这里你想使用它你最好使用flush而不是关闭它在finally 块中。

    【讨论】:

      【解决方案3】:

      根据您的问题,我认为您已经知道(或至少可能存在)一个缓冲区,该缓冲区在 flushclose 上被刷新。

      至于何时自动刷新,JavaDoc on PrintWriter 说:

      与 PrintStream 类不同,如果启用了自动刷新,它将仅在调用 println、printf 或格式方法之一时完成,而不是在碰巧输出换行符时完成。

      现在,缓冲如何以及是否发生取决于使用的底层 OutputStream(可以通过构造函数指定)。如果您使用BufferedOutputStream,您可以指定缓冲区的大小。虽然文档中没有明确提及,但是当缓冲区已满时也会发生刷新。

      您在示例中使用的 PrintWriter constructor taking a File 表示

      用指定的文件创建一个新的 PrintWriter,不自动刷新行。这个方便的构造函数创建了必要的中间 OutputStreamWriter,它将使用 Java 虚拟机的这个实例的默认字符集对字符进行编码。

      不对它将创建什么OutputStreamWriter 以及它将使用哪些设置做出任何额外的保证。

      【讨论】:

        猜你喜欢
        • 2021-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多