Как эффективно конвертировать кодировку символов в канале? - PullRequest
2 голосов
/ 11 апреля 2011

Мне нужно принимать потоки с разными кодировками и транскодировать их в одну предопределенную кодировку (например, 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 Ответ

0 голосов
/ 13 марта 2013

Для повышения производительности вышеуказанного кода:

  1. Кэшировать байтовые / символьные буферы в локальном потоке или в виде полей.Выделение фрагментов памяти стоит дорого.
  2. Прямые байтовые буферы - хорошие показатели для ввода-вывода, но плохие показатели для кодирования / декодирования, в которых оптимизирована реализация для буферов кучи.Вы можете получить более высокую производительность, копируя в / из буфера кучи байтов для операций декодирования / кодирования.
  3. Вы можете пропустить кодирование / декодирование, когда кодировка одинакова.
  4. Минимизируйте вызовы в compact.
  5. У вас, кажется, есть избыточные операции декодирования / кодирования после того, как в буфере ничего не осталось.
  6. Размер байтового буфера должен быть в 4 раза больше размера буфера символов, символ может быть 1-4 байта.Кроме того, выделение байтовых буферов, кратных размеру страницы (обычно 4 КБ), может повысить производительность ввода-вывода.

Самое главное, написать эталонный тест с реалистичными данными и использовать его в качестве средства измерения повышения производительности.Если вы не будете измерять, вы никогда не узнаете, что сработало.

...