2013-08-29 1 views
6

Я хочу написать CharSequence для OutputStream с помощью указанного CharSet. В принципе, сценарий, инициализированный тем же CharSet, будет делать, когда вызывается запись (String).Как закодировать CharSequence с помощью CharSet (без преобразования в String)

Улов есть, есть много CharSequences, которые должны быть написаны, а некоторые довольно большие. Чтобы усложнить ситуацию, все может быть записано в несколько продуктов OutputStream. Я могу легко осуществить, что при использовании (на самом деле я в настоящее время реализовал это таким образом):

byte[] rawBytes = CharSequence.toString().getBytes(CharSet) 
for (OutputStream out : outputTargets) { 
    out.write(rawBytes); 
} 

Но очевидно, что строка является полностью нежелательным объектом мусора здесь, как байты [] массив. Я ищу метод, который позволяет мне делать кодирование напрямую без промежуточных объектов. Удивительно, но это кажется невозможным - везде, где я смотрел в JRE, где CharSequence принимается, он быстро преобразуется в String до того, как будет выполнена какая-либо работа.

Большинство (все?) Операций преобразования для CharSet, по-видимому, выполняются в непубличных классах, поэтому я не нашел доступа к любому из них прозрачным и законным способом.

Как избежать мусора/использовать средства кодирования JRE CharSet напрямую?

+0

см. CharsetEncoder – ZhongYu

ответ

6

Итерации над символами последовательности и запись их писателю.

OutputStream outputStream = .... 
CharSequence charSequence = .... 
Charset charset = .... 

Writer writer = new OutputStreamWriter(outputStream, charset); 

for (int i = 0; i < charSequence.length(); i++) { 
    writer.write(charSequence.charAt(i)); 
} 
+0

Я не хотел этого делать (поскольку он требует от меня каких-то изменений в дизайне), но после некоторого раздумья это кажется самым простым, но резонно эффективным способом (если позаботиться о том, чтобы OutputStreams были обеспечены буферизуется). – Durandal

5

Вы можете использовать Charset для кодирования CharSequence в массив байтов:

private static byte[] encodeUtf8(CharSequence cs) { 
    ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(cs)); 
    byte[] result = new byte[bb.remaining()]; 
    bb.get(result); 
    return result; 
} 

Если вместо OutputStream, вы используете экземпляр WritableByteChannel, его метод write принимает ByteBuffer непосредственно, так вам даже не нужно сначала копировать байтовый буфер в массив байтов.

+1

Я считаю, что OP хочет избежать создания массива байтов в памяти для всей последовательности. Представьте, что CharSequence в 10 раз больше, чем доступная оперативная память. В этом случае этот метод не будет работать, правильно? – Keith

+1

Это справедливая точка, и хороший вариант использования для вашего решения (+1). –

+0

Ну, мои CharSequences, как правило, не такие большие (несколько K, но они часты и генерируют много лишнего мусора). Существует также жесткая кепка из-за метода length(), возвращающего int, что мешает отображать большой текстовый файл как CharSequence. Идея с CharBuffer.wrap(), хотя я не буду использовать ее для этой конкретной проблемы, может оказаться полезной в других ситуациях. – Durandal