Преобразование потока байтов в поток символов в Java - PullRequest
2 голосов
/ 21 января 2011

Существует ли класс, в котором можно создать его, указав кодировку, направить в него потоки байтов и получить из него потоки символов? Суть в том, что я хочу сохранить память, не имея в памяти одновременно и всех данных потока байтов и данных потока символов.

Что-то вроде:

Something s = new Something("utf-8");
s.write(buffer, 0, buffer.length); // it converts the bytes directly to characters internally, so we don't store both
// ... several more s.write() calls
s.close(); // or not needed

String text = s.getString();
// or
char[] text = s.getCharArray();

Что это такое Something?

Ответы [ 4 ]

7 голосов
/ 21 января 2011

Вы ищете ByteArrayInputStream? Затем вы можете обернуть это в InputStreamReader и прочитать символы из исходного байтового массива.

A ByteArrayInputStream позволяет вам "поток" из байтового массива. Если вы поместите это в InputStreamReader, вы сможете читать символы. InputStreamReader позволяет указать кодировку символов.

Если вы хотите перейти напрямую из входного источника байтов, то вы можете просто создать соответствующий класс InputStream (например, FileInputStream) и затем обернуть его в InputStreamReader.

4 голосов
/ 21 января 2011

Вы, вероятно, можете смоделировать это, используя CharsetDecoder.Что-то вроде

    CharsetDecoder decoder = Charset.forName(encoding).newDecoder();
    CharBuffer cb = CharBuffer.allocate(100);
    decoder.decode(ByteBuffer.wrap(buffer1), cb, false);
    decoder.decode(ByteBuffer.wrap(buffer2), cb, false);
    ...
    decoder.decode(ByteBuffer.wrap(bufferN), cb, true);
    cb.position(0);
    return cb.toString();

(Да, я знаю, что это переполнит вашу CharBuffer - вы можете скопировать содержимое в StringBuilder по мере продвижения.)

1 голос
/ 21 января 2011

На самом деле заголовок " Преобразование байтового потока в символьный поток в Java " противоречит вашему примеру, вообще не используя потоков, но массивы . Я предполагаю, что дальше вы хотите массивы.

Вы, конечно, не можете начинать с байта [] и заканчиваться символом [] (или строкой), не имея какое-то время какое-то время. Однако есть несколько возможностей:

  • на тот случай, если вам действительно нужен char[]: Идея: записать байт [] в файл и прочитать его с помощью FileReader в массив. Это на самом деле не работает, так как вы заранее не знаете правильную длину массива. Поэтому сгенерируйте и запишите все символы в файл, используя DataOutput, прочитайте все их обратно, используя DataInput, в массив.

  • на тот случай, если вам действительно нужно String: создайте char[], как указано выше, и используйте отражение и setAccessibe(true) для вызова частного пакета ctor String(int offset, int count, char value[]).

  • в случае, если достаточно CharSequence: создайте класс MyCharSequence, содержащий байт []. Чрезвычайно медленным решением было бы реализовать его метод charAt(index) путем преобразования части байта [], начиная с начала до получения index+1 символов. Откажитесь от всех на лету и оставьте последний. Такой глупый метод необходим, поскольку, используя utf8, вы не знаете, сколько байтов соответствует одному символу. Вы можете сделать это один раз в начале и запомнить для каждого символа позицию своего первого байта. Это еще более глупо, так как вам понадобится гораздо больше памяти для этих позиций. К счастью, существует простой пространственно-временной компромисс, например, запомните позицию первого байта для каждого 16-го символа.

Все мои предложения немного странные, но я считаю, что это не может быть сделано намного лучше. Это может быть забавное домашнее задание, я бы на это не пошла.

1 голос
/ 21 января 2011

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

char[] chars = s.toCharArray();
byte[] bytes = s.getBytes("utf-8");

Затем вопрос сводится к тому, как получить байты из потока байтов в String, для которого вы можете использовать ByteArrayOutputStream, например:

ByteArrayOutputSteam os = new ByteArrayOutputSteam();
os.write(buffer, 0, buffer.length); // it just stores the bytes, doesn't convert yet.
// several more os.write() calls
s = os.toString("utf-8"); // now it converts the full buffer to a string in the specified encoding.

Если вы действительно хотите что-то, имеющее поток ввода байтов и поток вывода символов, встроенного нет.

...