为什么以下方法会挂起?

public void pipe(Reader in, Writer out) {
    CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
    while( in.read(buf) >= 0 ) {
      out.append(buf.flip());
    }
}
有帮助吗?

解决方案

回答我自己的问题:你必须在 read 之间调用 buf.clear()。据推测, read 挂起,因为缓冲区已满。正确的代码是

public void pipe(Reader in, Writer out) {
    CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
    while( in.read(buf) >= 0 ) {
      out.append(buf.flip());
      buf.clear();
    }
}

其他提示

我认为这是一个僵局。 in.read(buf)锁定CharBuffer并阻止out.append(buf)调用。

假设CharBuffer在实现中使用了锁(某种)。 API对CharBuffer类有什么看法?

编辑:对不起,我脑子里有某种短路......我把它与其他东西混淆了。

CharBuffers不能像你期望的那样干净利落地阅读和写作。特别是,没有 Writer.append(CharBuffer buf)方法。问题片段调用的方法是 Writer.append(CharSequence seq),它只调用 seq.toString() CharBuffer.toString()方法确实返回缓冲区的字符串值,但它不会耗尽缓冲区。随后对 Reader.read(CharBuffer buf)的调用得到一个已经完整的缓冲区,因此返回0,迫使循环无限期地继续。

虽然这感觉像挂起,但实际上每次通过循环时都会将第一个读取的缓冲区内容附加到编写器。所以你要么开始在你的目的地看到很多输出,要么编写器的内部缓冲区会增长,这取决于编写器的实现方式。

虽然很烦人,但我建议使用char []实现,因为CharBuffer解决方案每次通过循环时都会建立至少两个新的char []。

public void pipe(Reader in, Writer out) throws IOException {
    char[] buf = new char[DEFAULT_BUFFER_SIZE];
    int count = in.read(buf);
    while( count >= 0 ) {
        out.write(buf, 0, count);
        count = in.read(buf);
    }
}

如果你需要支持在两个字符编码之间进行转换,我建议只使用它,否则即使你管道符号,ByteBuffer / Channel或byte [] / IOStream实现也会更好。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top