Java + Eclipse:同步stdout和stderr
我用Eclipse。 当我有这样的应用程序时:
write 20 times 'Hello World\n' to stdout write 'ERROR\n' to stderr write 5 times 'Hello World\n' to stdout
输出看起来很多次像这样:
Hello World Hello World Hello World Hello World Hello World Hello World ... Hello World Hello World Hello World ERROR
有没有办法同步这两个输出流? 当然,在20次Hello World
块之后没有等待几毫秒,并在打印ERROR
后等待几毫秒。
信不信由你,冲洗不是解决方案….
如果流导致“底层操作系统提供的抽象”(例如磁盘驱动器或控制台),那么剩余的字节“将被传递给操作系统进行写入;它不能保证它们实际被写入……”(请参阅OutputStream文档 )。 这里的关键是操作系统可以按照不同的顺序处理来自不同流的刷新。
我只是在我的程序中发生了这种情况。 我在两条正常消息之间出现了一条错误消息,这两条消息都在错误消息之前刷新了。
所以问题仍然存在,是否存在同步两个流的内置方法? 或者我们必须手动处理?
对于“严肃”的使用,我不喜欢直接写入System.out/System.err
,因为它硬编码目的地,它也使用相当古怪的PrintStream
(它是字节流还是字符流?)。 如果将输出流包装在自己的PrintWriter
,则可以将其设置为自动刷新 – 构造函数中的第二个参数是auto-flush
。
例如
PrintWriter out = new PrintWriter(System.out, true); PrintWriter err = new PrintWriter(System.err, true); out.println("Hello world"); //this will flush after writing the end of line
看到
- java.io.PrintWriter ,javadoc Java SE 6
- PrintWriter和PrintStream之间的差异 ,SO问题
System.out和System.err是普通的PrintStream
对象(提供flush()方法),因此请尝试System.out.flush()
和System.err.flush()
。
AFAIK没有可靠的方法强制同步2个不相关的流。
解决方法是仅使用一个流:例如,使用System.setErr()重定向到错误,以便在错误流上打印所有内容:
System.setErr(System.out);
或者通过System.setOut()反过来
System.setOut(System.err);
这样做的缺点是它可能会改变语法突出显示:例如,某些IDE可能会以不同方式突出显示stderr和stdout上的文本
添加一个刷新后跟一个Thread.sleep(1)
,99.9%的输出顺序是正确的。
例如,这将按预期显示。
System.out.println( "stdout 1" ); System.out.flush(); Thread.sleep( 1 ); System.err.println( "stderr 1" ); System.err.flush(); Thread.sleep( 1 ); System.out.println( "stdout 2" ); System.out.flush(); Thread.sleep( 1 ); System.err.println( "stderr 2" ); System.err.flush(); Thread.sleep( 1 );
唯一的缺点是睡眠时间为1毫秒,即1/1000秒