我需要接受具有不同编码的流并将它们转码为单一的预定义编码(例如 UTF-8)。我知道如何使用 (InputStream
)Reader
/(OutputStream
)Writer
组合和数组缓冲区来做到这一点,但是这次我要处理 ByteChannel
的。当然,我正在研究 CharsetDecoder
/CharsetEncoding
解决方案,但我得到的最好的是:
public static void copy(ReadableByteChannel rbc, Charset in,
WritableByteChannel wbc, Charset out) throws IOException {
ByteBuffer b1 = ByteBuffer.allocateDirect(BUFFER_SIZE);
CharBuffer cb = CharBuffer.allocate(BUFFER_SIZE);
ByteBuffer b2 = ByteBuffer.allocateDirect(BUFFER_SIZE);
CharsetDecoder decoder = in.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE);
CharsetEncoder encoder = out.newEncoder();
encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
while( rbc.read(b1)!=-1 ){
b1.flip();
decoder.decode(b1, cb, false);
cb.flip();
encoder.encode(cb, b2, false);
b2.flip();
wbc.write(b2);
b2.compact();
cb.compact();
b1.compact();
}
b1.flip();
while (b1.hasRemaining()){
decoder.decode(b1, cb, true);
cb.flip();
encoder.encode(cb, b2, false);
b2.flip();
wbc.write(b2);
b2.compact();
cb.compact();
}
decoder.decode(b1, cb, true);
decoder.flush(cb);
cb.flip();
while (cb.hasRemaining()){
encoder.encode(cb, b2, true);
b2.flip();
wbc.write(b2);
b2.compact();
}
encoder.encode(cb, b2, true);
encoder.flush(b2);
b2.flip();
while (b2.hasRemaining()){
wbc.write(b2);
}
}
由于此方法在项目中是“主力”,我必须绝对确定无论 BUFFER_SIZE、编码和输出阻塞设备的组合如何,它都能完成。
我的问题是:
- 有没有更好的缓冲区耗尽方法来代替这些级联的 while 循环?
- 是否可以忽略
encode()
/decode()
结果(对于上溢和下溢)?
当然,欢迎任何替代想法。 :)
最佳答案
提高上述代码的性能:
- 在线程本地或作为字段缓存字节/字符缓冲区。分配内存块非常昂贵。
- 直接字节缓冲区在 IO 方面表现良好,但在编码/解码方面表现不佳,它具有针对堆缓冲区的优化实现。通过为解码/编码操作复制到堆字节缓冲区或从堆字节缓冲区复制,您可能会获得更好的性能。
- 当字符集相同时,您可以跳过编码/解码。
- 尽量减少对 compact 的调用。
- 在缓冲区没有任何剩余后,您似乎有多余的解码/编码操作。
- 字节缓冲区大小应该是字符缓冲区大小的 4 倍,字符可以是 1-4 个字节。此外,将字节缓冲区分配为页面大小的倍数(通常为 4k)有助于提高 IO 性能。
最重要的是,使用真实数据编写基准并将其用作衡量性能改进的方法。如果您不衡量,您将永远不知道什么有效。
关于java - Channel中如何高效转换字符编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5624847/