java - Channel中如何高效转换字符编码?

标签 java performance character-encoding nio

我需要接受具有不同编码的流​​并将它们转码为单一的预定义编码(例如 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() 结果(对于上溢和下溢)?

当然,欢迎任何替代想法。 :)

最佳答案

提高上述代码的性能:

  1. 在线程本地或作为字段缓存字节/字符缓冲区。分配内存块非常昂贵。
  2. 直接字节缓冲区在 IO 方面表现良好,但在编码/解码方面表现不佳,它具有针对堆缓冲区的优化实现。通过为解码/编码操作复制到堆字节缓冲区或从堆字节缓冲区复制,您可能会获得更好的性能。
  3. 当字符集相同时,您可以跳过编码/解码。
  4. 尽量减少对 compact 的调用。
  5. 在缓冲区没有任何剩余后,您似乎有多余的解码/编码操作。
  6. 字节缓冲区大小应该是字符缓冲区大小的 4 倍,字符可以是 1-4 个字节。此外,将字节缓冲区分配为页面大小的倍数(通常为 4k)有助于提高 IO 性能。

最重要的是,使用真实数据编写基准并将其用作衡量性能改进的方法。如果您不衡量,您将永远不知道什么有效。

关于java - Channel中如何高效转换字符编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5624847/

相关文章:

java - 在Java中,使用从InputStream.read()返回的int来调用Character.isXxx()方法是否安全?

java - 如何从存储在服务器上的表中检索列值?

Java swing setSelectionForeground 性能问题

node.js - 在 Redis 中存储对象(nodeJS)有很多变化

http - tomcat的字符编码问题

javascript - 为什么此字符编码问题只发生在特定系统上?

java - 如果打印的话 byte b=(byte)0x8A 的值是多少?

java - 从 session Java 访问数组

javascript - 如何提高字典的性能?

javascript - 为什么 Node.js 会将 BOM 字符转换为 0xFE 0xFF?