多个引号会导致PipedOutputStream / OutputStreamWriter失败

时间:2014-11-27 13:15:44

标签: java stream

当我尝试将PipedOutputStream复制到OutputStream时,我偶然发现InputStream的一个非常奇怪的行为。另请参阅How to write an nt:file programmatically

这是一个小单元测试方法:

@Test
public void pipeTest() {
    PipedInputStream pin = null;
    try {
        pin = new PipedInputStream();
        PipedOutputStream pout = new PipedOutputStream(pin);
        OutputStreamWriter writer = new OutputStreamWriter(pout);
        for (int i = 0; i < 100; i++) {
            writer.write("\"Test\";" + i + "\n");
            // writer.write("\"Test\";" + "\"" + i + "\"\n");
        }

        writer.close();
        pout.close();

        System.out.print(IOUtils.toString(pin));
    } catch (IOException e) {
        System.out.print(e);
    } finally {
        IOUtils.closeQuietly(pin);
    }

}

效果很好,打印出100行。如果取消注释第二个写入语句并注释掉第一个,writer.close()会卡住并且永远不会完成。它似乎与第二组引号\"有问题。 有没有人知道为什么会这样,以及如何规避它?

2 个答案:

答案 0 :(得分:3)

这与引号无关 - 而且与您正在编写的数据量有关。为了证明这一点,你可以完全摆脱编写器和循环,只需使用:

pout.write(new byte[1024]);

或保留现有代码,但看到这有效(因为它写了1000个字节):

writer.write("0123456789");

但这没有(因为它试图写1100字节):

writer.write("0123456789X");

可行 - 但是如果你将它改为1025,它将永远挂起......因为默认情况下内部缓冲区长度为1024字节,并且没有任何消耗流。 (在完成写入之前,你不会从pin读取。)由于没有任何消耗前1024个字节中的任何一个,所以无处放置第1025个字节,所以write阻塞直到空间。

你可以:

  • 在构造PipedInputStream时更改管道大小,因此它有一个更大的缓冲区
  • 在写作时从管道中读取 - 例如在一个单独的主题中。

答案 1 :(得分:0)

PipedInputStream有一个内部缓冲区。默认情况下,缓冲区为1024字节,但您可以将不同的大小传递给PipedInputStream的构造函数。

当缓冲区已满时,写入与PipedOutputStream块关联的PipedInputStream,直到您从后者读取足够的数据,以便缓冲区中有空间

你的问题与双引号本身无关;它只是你添加双引号时写的更多数据。

您应该只在多线程代码中使用管道流(其中一个线程写入管道输出流,另一个线程从管道输入流中读取),以避免这种可能的死锁。

PipedInputStream的Javadoc对此有明确警告:

  

尝试同时使用单个线程中的两个对象   建议,因为它可能使线程死锁。