当前位置: 首页 > 知识库问答 >
问题:

系统出来立即将输出打印到控制台。所以每次打印后PrintStream都会刷新,而不仅仅是println?

司寇嘉茂
2023-03-14

从PrintStream文档中:

可选地,可以创建打印流以便自动刷新;这意味着在写入字节数组、调用某个println方法或写入换行符或字节('\n')后,会自动调用flush方法。

然后给出代码

System.out.print("hi");   // gives console output: hi
System.out.print(7);      // gives console output: 7

// prevents flushing when stream wiil be closed at app shutdown
for (;;) {
}

为什么我会看到控制台的输出?不应将任何内容写入控制台(System.out中的PrintStream实例),因为到目前为止不应刷新任何内容!

这不是答案。

我猜,答案是在源代码(私有实用程序方法BufferedWriter.flushBuffer()),但我不明白代码的注释:“将输出缓冲区刷新到底层字符流,而不刷新流本身”:如果PrintStream(与控制台输出绑定),即“流本身”未刷新,则不得刷新输出到控制台!...

PrintStream的源代码。打印(字符串):

private void write(String s) {
        try {
            synchronized (this) {
                ensureOpen();
                textOut.write(s);
                textOut.flushBuffer();
                charOut.flushBuffer();
                if (autoFlush && (s.indexOf('\n') >= 0))
                    out.flush();
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }

BufferedWriter的源代码。flushBuffer():

/**
     * Flushes the output buffer to the underlying character stream, without
     * flushing the stream itself.  This method is non-private only so that it
     * may be invoked by PrintStream.
     */
    void flushBuffer() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar == 0)
                return;
            out.write(cb, 0, nextChar);
            nextChar = 0;
        }
    }

这里还提供了更多细节。这非常复杂,但似乎在某个阶段,BufferedWriter被赋予了PrintStream构造函数

共有2个答案

曹鹏海
2023-03-14

https://bugs.openjdk.java.net/browse/JDK-8025883描述了这个错误。

这让我在一个读取和解析二进制文件的程序中受益匪浅,在系统中执行了大量的。出来printf()调用,这需要更长的时间。

最后我写了一个helper类,它违反了Streams的约定,没有满足每个flush请求:

class ForceBufferedOutputStream extends OutputStream {

    OutputStream out;
    byte[] buffer;
    int buflen;
    boolean haveNewline;
    private static final int bufsize=16384;

    public ForceBufferedOutputStream(OutputStream out) {
        this.out=out;
        this.buffer=new byte[bufsize];
        this.buflen=0;
        this.haveNewline=false;
    }
    @Override
    public void flush() throws IOException {
        if (this.haveNewline || this.buflen==bufsize) {
            out.write(buffer, 0, buflen);
            out.flush();
            this.buflen=0;
            this.haveNewline=false;
        }
    }
    @Override
    public void close() throws IOException {
        out.close();
    }

    @Override
    public void write(int b) throws IOException {
        buffer[buflen++]=(byte)b;
        if (b=='\n')
            this.haveNewline=true;
        if (buflen==bufsize)
            this.flush();
    }
}

然后使用new PrintStream(new ForceBufferedOutputStream(System.out))代替System.out

我认为这是一个可怕的软件——正如前面所说,它违反了合同,即flush()需要确保所有内容都已写入,并且它可以优化数组写入调用。但在我的例子中,运行时间从17分钟缩短到了3:45,所以如果你需要一个能加速快速而肮脏的程序的复制/粘贴,我希望它能有所帮助。

公良育
2023-03-14

其中,缺少关于\n的检查。

流程如下:

  1. System.out#print(String s)调用PrintStream#print(String s)
  2. PrintStream#print(String s)调用PrintStream#write(String s)
  3. PrintStream#write(String s)调用OutputSteamWriter#flushBuffer()
  4. OutputStreamWriter#flushBuffer()调用StreamEncoder#flushBuffer()
  5. StreamEncoder#flushBuffer()调用StreamEncoder#implFlushBuffer()
  6. StreamEncoder#implFlushBuffer()调用StreamEncoder#WriteBytes()
  7. StreamEncoder#WriteBytes()调用PrintStream#write(byte buf[], int off, int len)刷新bufforif(autoFlush)

最重要的片段在上面。BufferedWriter似乎没有在此流程中调用。

 类似资料:
  • 我如何才能使打印在控制台中的消息不是直接发出,而是一点一点地发出

  • 我在NetBeans IDE中使用Java编写了一个简单的程序。在今天早上对main方法做了一些更改后,当我运行程序时,控制台不会打印任何东西。我只是想让它到达startMenus(sc)。编辑:我现在已经放入了一些system.out.println(),但它没有达到“blah2”,就在我的第一个循环之后...

  • 我有一个在Wildfly 8.*上运行的Spring Web应用程序,由于某种原因,它不会打印到控制台。我看到所有控制台日志和堆栈跟踪都很好,但系统消息只是没有出现。 问题可能出在我的log4j设置上,所以我会发布该配置; 我以前在JBoss 7.1上运行过应用程序,但是没有这个问题,所以我真的不知道可能出了什么问题。 随意询问我的任何其他配置不确定需要什么。 编辑: 这是我的独立部署文件夹中的日

  • 问题语句:我有一个在Xcode中运行的程序,它有一堆print()语句,可以很好地将输出打印到调试控制台。然而,我希望也能够将这些输出重定向到一个文件,这样我就可以让用户将它们发送给我,作为调试的一种方式。 SO上找到的解决方案使我可以将输出重定向到文件,但调试控制台输出将丢失。 问:我想要我的蛋糕和吃它。我希望能够将print()语句重定向到调试控制台和文件。 所以我有引用:https://st

  • 问题内容: 我有一个类,我们称它为Cls,其中包含一些值。当我使用声明为的Gson实例并将其用于序列化Cls对象并将结果JSON字符串打印到控制台时,我得到了格式正确的格式,如下所示: 这一切都很好,但是当我然后创建一个JsonWriter(从具有绝对路径的FileWriter)并使用带有Cls 的Gson实例的方法时,生成的文件就不会得到很好的格式化。相反,它看起来像这样: 这打败了漂亮印刷的全