为什么以下方法会挂起?
公共无效管道(读入,写出){ CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); 而(in.read(buf)> = 0){ out.append(buf.flip()); } }
回答我自己的问题:你必须在 sbuf.clear()
之间调用read
。据推测,read
是因为缓冲区已满而挂起。正确的代码是
公共无效管道(读入,写出){ CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); 而(in.read(buf)> = 0){ out.append(buf.flip()); buf.clear(); } }
我认为这是一个僵局。in.read(buf) 锁定 CharBuffer 并阻止 out.append(buf) 调用。
这是假设 CharBuffer 在实现中使用锁(某种)。API 对 CharBuffer 类有什么看法?
编辑:对不起,我的大脑短路了……我把它和别的东西弄混了。
CharBuffers 不能像您期望的那样干净地与 Readers 和 Writers 一起工作。特别是没有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 实现。