Строка Java разделения в блоках 1 024 байтов

with open('alpha.txt', 'rt') as a:
    t = a.read()
    print(t)

работает. Что за вопрос здесь?

7
задан user54729 6 February 2009 в 16:10
поделиться

2 ответа

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

Что Вы на самом деле хотите сделать?

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

Можно или разделить Строку на блоки 1 024 символов и закодировать тех, которые как байты, но затем каждый блок может составить больше чем 1 024 байта.

Или можно закодировать исходную строку в байты и затем разделить их на блоки 1 024, но затем необходимо удостовериться, что добавили их как байты прежде, чем декодировать целое в Строку снова, или можно получить искаженные символы в точках разделения, когда символ охватывает больше чем 1 байт.

Если Вы волнуетесь по поводу использования памяти, когда Строка может быть очень длинной, необходимо использовать потоки (java.io пакет) к к en/decoding и разделению, чтобы не сохранять данные в памяти несколько раз как копии. Идеально, необходимо постараться не иметь исходную строку в одной части вообще и вместо этого использовать потоки для чтения ее в маленьких блоках от того, везде, где Вы получаете ее от.

5
ответ дан 6 December 2019 в 11:53
поделиться

У Вас есть два пути, быстрое и консерватор памяти путь. Но сначала, необходимо знать, какие символы находятся в Строке. 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));

Обратите внимание, что Строка является Unicode, таким образом, для каждого символа нужны два байта. Необходимо будет указать кодирование (не полагайтесь на "значение по умолчанию платформы". Это будет только причинять боль позже).

Теперь можно считать его в 1 024 использованиях блоков

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > 0) { ... }

Этому нужно приблизительно в три раза больше RAM, чем исходная строка.

Больше пути консерватора памяти состоит в том, чтобы записать преобразователь, который берет 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 ...

Этому только нужны несколько килобайтов RAM.

[РЕДАКТИРОВАНИЕ] Там было долгой дискуссией о двоичных данных в Строках в комментариях. В первую очередь, совершенно безопасно поместить двоичные данные в Строку, пока Вы осторожны при создании его и хранении его где-нибудь. Для создания такой Строки возьмите байт [] массив и:

String safe = new String (array, "iso-8859-1");

В Java ISO-8859-1 (иначе ISO-Latin1) 1:1 отображение. Это означает, что байты в массиве не будут интерпретироваться всегда. Теперь можно использовать подстроку () и т.п. на данных или искать его с индексом, выполнить regexp's на нем и т.д. Например, найдите положение 0 байтов:

int pos = safe.indexOf('\u0000');

Это особенно полезно, если Вы не знаете кодирование данных и хотите взглянуть на него перед некоторой путаницей кодека с ним.

Для записи данных где-нибудь обратная операция:

байт [] данные = safe.getBytes ("iso-8859-1");

Никогда не используйте методы по умолчанию new String(array) или String.getBytes()! Однажды, Ваш код будет выполняемым на другой платформе, и он повредится.

Теперь проблема символов> 255 в Строке. При использовании этого метода у Вас никогда не будет никакого подобного символа в Ваших Строках. Тем не менее, если бы был кто-либо по некоторым причинам, то getBytes () выдал бы Исключение, потому что нет никакого способа выразить все символы Unicode в ISO-Latin1, таким образом, Вы в безопасности в том смысле, что код не перестанет работать тихо.

Некоторые могли бы утверждать, что это не достаточно безопасно, и Вы никогда не должны смешивать байты и Строку. В этот день возраст, у нас нет той роскоши. Много данных не имеет никакой явной информации о кодировании (файлы, например, не имейте атрибута "кодирования" таким же образом, как у них есть права доступа или имя). XML является одним из нескольких форматов, который имеет явную информацию о кодировании и существуют редакторы как Emacs или jEdit, которые используют комментарии для определения этой важной информации. Это означает, что при обработке потоков байтов необходимо всегда знать, в котором кодировании они. На данный момент не возможно написать код, который будет всегда работать, неважно, куда данные прибывают из.

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

Важный момент должен сесть и выяснить, какое кодирование использовалось для генерации потока данных, который необходимо обработать. Если Вы делаете это, Вы хороши, если Вы не делаете, Вы обречены. Беспорядок происходит из того, что большинство людей не знает, что тот же байт может означать разные вещи в зависимости от кодирования или даже что существует больше чем одно кодирование. Кроме того, помогло бы, не представил ли Sun понятие "кодировки по умолчанию платформы".

Важные моменты для новичков:

  • Существует больше чем одно кодирование (набор символов).
  • Существует больше символов, чем английское использование языка. Существует даже несколько наборов цифр (ASCII, полная ширина, арабская относящаяся к Индии, бенгальская).
  • Необходимо знать, какое кодирование использовалось для генерации данных, которые Вы обрабатываете.
  • Необходимо знать, какое кодирование необходимо использовать для записи данных, которые Вы обрабатываете.
  • Необходимо знать корректный способ указать эту информацию о кодировании, таким образом, следующая программа может декодировать вывод (заголовок XML, метатег HTML, специальный комментарий кодирования, безотносительно).

Дни ASCII закончены.

9
ответ дан 6 December 2019 в 11:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: