У вас есть два способа: быстрый и консервативный. Но сначала вам нужно знать, какие символы находятся в строке. ASCII? Есть ли умляуты (символы между 128 и 255) или даже Unicode (s.getChar () возвращает что-то> 256). В зависимости от этого вам нужно будет использовать другую кодировку. Если у вас есть двоичные данные, попробуйте «iso-8859-1», потому что он сохранит данные в строке. Если у вас есть Unicode, попробуйте «utf-8». Я приму двоичные данные:
String encoding = "iso-8859-1";
Самый быстрый способ:
ByteArrayInputStream in = new ByteArrayInputStream (string.getBytes(encoding));
Обратите внимание, что String является Unicode, поэтому каждому символу требуется два байта. Вам нужно будет указать кодировку (не полагайтесь на «платформу по умолчанию». Это только потом вызовет боль).
Теперь вы можете прочитать его в 1024 кусках, используя
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) { ... }
Для этого требуется примерно в три раза больше оперативной памяти, чем для исходной строки.
Более консервативный способ памяти - написать конвертер, который принимает StringReader и OutputStreamWriter (который оборачивает ByteArrayOutputStream). Скопируйте байты из читателя в записывающее устройство до тех пор, пока нижележащий буфер не будет содержать один кусок данных:
Когда это произойдет, скопируйте данные в реальный вывод (с добавлением заголовка), скопируйте дополнительные байты (которые, возможно, сгенерировал преобразование байтов Unicode->) во временный буфер, вызовите buffer.reset () и запишите временный буфер в буфер.
Код выглядит следующим образом (не проверено):
StringReader r = new StringReader (string);
ByteArrayOutputStream buffer = new ByteArrayOutputStream (1024*2); // Twice as large as necessary
OutputStreamWriter w = new OutputStreamWriter (buffer, encoding);
char[] cbuf = new char[100];
byte[] tempBuf;
int len;
while ((len = r.read(cbuf, 0, cbuf.length)) > 0) {
w.write(cbuf, 0, len);
w.flush();
if (buffer.size()) >= 1024) {
tempBuf = buffer.toByteArray();
... ready to process one chunk ...
buffer.reset();
if (tempBuf.length > 1024) {
buffer.write(tempBuf, 1024, tempBuf.length - 1024);
}
}
}
... check if some data is left in buffer and process that, too ...
Для этого требуется всего несколько килобайт оперативной памяти.
[РЕДАКТИРОВАТЬ] В комментариях было долгое обсуждение двоичных данных в строках. Прежде всего, совершенно безопасно помещать двоичные данные в строку, если вы осторожны при их создании и хранении где-либо. Чтобы создать такую строку, возьмите массив byte [] и:
String safe = new String (array, "iso-8859-1");
В Java ISO-8859-1 (a.k.a ISO-Latin1) является отображением 1: 1. Это означает, что байты в массиве не будут интерпретироваться каким-либо образом. Теперь вы можете использовать substring () и т. П. В данных или искать их по индексу, выполнять для них регулярные выражения и т. Д. Например, найдите позицию 0-байта:
int pos = safe.indexOf('\u0000');
Это особенно полезно, если вы не знаете кодировку данных и хотите взглянуть на них до того, как какой-то кодек с ними замешается.
Чтобы записать данные куда-нибудь, обратная операция:
byte [] data = safe.getBytes ("iso-8859-1");
Никогда не используйте методы по умолчанию new String(array)
или String.getBytes()
! Однажды ваш код будет выполнен на другой платформе и он сломается.
Теперь проблема символов> 255 в строке. Если вы используете этот метод, у вас никогда не будет такого символа в ваших строках. Тем не менее, если бы они были по какой-либо причине, то getBytes () сгенерировал бы исключение, потому что нет способа выразить все символы Unicode в ISO-Latin1, так что вы в безопасности в том смысле, что код не потерпит молчания.
Некоторые могут утверждать, что это недостаточно безопасно, и вы никогда не должны смешивать байты и строку. В наши дни, у нас нет такой роскоши. Многие данные не имеют явной информации о кодировании (например, файлы не имеют атрибута «кодировка» так же, как они имеют права доступа или имя). XML - один из немногих форматов, который имеет явную информацию о кодировке, и есть редакторы, такие как Emacs или jEdit, которые используют комментарии для указания этой важной информации. Это означает, что при обработке потоков байтов вы всегда должны знать, в какой кодировке они находятся. На данный момент невозможно написать код, который будет работать всегда, независимо от того, откуда поступают данные.
Даже с XML вы должны прочитать заголовок файла в байтах, чтобы определить кодировку, прежде чем сможете декодировать мясо.
Важным моментом является сесть и выяснить, какая кодировка использовалась для генерации потока данных, который вы должны обработать. Если ты делаешь это, ты в порядке, если нет, ты обречен. Путаница возникает из-за того, что большинство людей не знают, что один и тот же байт может означать разные вещи в зависимости от кодировки или даже от того, что существует более одной кодировки. Кроме того, это помогло бы, если бы Sun не ввела понятие «кодировка платформы по умолчанию».
Важные моменты для начинающих:
- Существует более одной кодировки (кодировки).
- Есть больше символов, чем использует английский язык. Существует даже несколько наборов цифр (ASCII, полная ширина, арабский-индийский, бенгальский).
- Вы должны знать, какая кодировка использовалась для генерации данных, которые вы обрабатываете.
- Вы должны знать, какую кодировку следует использовать для записи данных, которые вы обрабатываете.
- Вы должны знать правильный способ указания этой информации о кодировке, чтобы следующая программа могла декодировать ваш вывод (заголовок XML, метатег HTML, специальный комментарий кодировки и т. Д.)
Дни ASCII прошли.