如何在Channel中有效地转换字符编码?

时间:2011-04-11 17:04:22

标签: java performance character-encoding nio

我需要接受具有不同编码的流​​,并将它们转码为单个预定义编码(例如UTF-8)。我知道如何使用(InputStreamReader /(OutputStreamWriter组合和数组缓冲区执行此操作,但这次我正在处理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 个答案:

答案 0 :(得分:0)

提高上述代码的效果:

  1. 在本地线程或字段中缓存字节/字符缓冲区。分配大块内存非常昂贵。
  2. 直接字节缓冲区是IO的良好执行者,但编码/解码的性能较差,具有针对堆缓冲区的优化实现。通过复制到堆字节缓冲区以进行解码/编码操作,可以获得更好的性能。
  3. 当charset相同时,您可以跳过编码/解码。
  4. 尽量减少对紧凑的调用。
  5. 在缓冲区没有剩余任何内容之后,您似乎有冗余的解码/编码操作。
  6. 字节缓冲区大小应为char缓冲区大小的4倍,chars可以是1-4个字节。另外,将字节缓冲区分配为页面大小的倍数(通常为4k)可以帮助IO性能。
  7. 最重要的是,使用实际数据编写基准,并将其用作衡量性能改进的方法。如果你不衡量,你将永远不知道什么有用。