2013-11-14 2 views
2

У меня есть некоторые большие кодированные данные base64 (хранятся в быстрых файлах в файловой системе hadoop). Эти данные были первоначально gzipped текстовыми данными. Мне нужно уметь читать фрагменты этих закодированных данных, декодировать их, а затем очищать их до GZIPOutputStream.Потоковое декодирование данных Base64

Любые идеи о том, как я мог это сделать, вместо того, чтобы загружать все данные base64 в массив и вызывать Base64.decodeBase64 (byte [])?

Я прав, если я прочитал символы до разделителя '\ r \ n' и расшифровал его по строкам? , например. :

for (int i = 0; i < byteData.length; i++) { 
    if (byteData[i] == CARRIAGE_RETURN || byteData[i] == NEWLINE) { 
     if (i < byteData.length - 1 && byteData[i + 1] == NEWLINE) 
      i += 2; 
     else 
      i += 1; 

     byteBuffer.put(Base64.decodeBase64(record)); 

     byteCounter = 0; 
     record = new byte[8192]; 
    } else { 
     record[byteCounter++] = byteData[i]; 
    } 
} 

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

Сейчас я пытаюсь поставить в InputStream, а затем скопировать в gzipout

byteBuffer.get(bufferBytes); 

InputStream inputStream = new ByteArrayInputStream(bufferBytes); 
inputStream = new GZIPInputStream(inputStream); 
IOUtils.copy(inputStream , gzipOutputStream); 

И это дает мне java.io.IOException: Коррумпированные GZIP прицеп

+0

'byteBuffer.put (Base64.decodeBase64 (запись));' Не должно быть, что 'byteBuffer.put (Base64.encodeBase64 (запись));' –

+0

'записи' кодируется в Base64. Я пытаюсь получить декодированные данные и добавить их в ByteBuffer. –

ответ

3

Пойдемте шаг за шагом:

  1. Вам нужен GZIPInputStream для чтения сжатые данные (которые и не GZIPOutputStream; выходной поток используется для сжатия данных). Имея этот поток, вы сможете прочитать несжатые исходные двоичные данные. Для этого требуется конструктор InputStream.

  2. Вам нужен поток ввода, способный считывать кодированные данные Base64. Я предлагаю удобный Base64InputStream от apache-commons-codec. С помощью конструктора вы можете установить длину линии, разделитель строк и установить doEncode=false для декодирования данных. Это, в свою очередь, требует другого входного потока - необработанных, закодированных Base64 данных.

  3. Этот поток зависит от того, как вы получаете данные; в идеале данные должны быть доступны как InputStream - проблема решена. Если нет, то вы, возможно, придется использовать ByteArrayInputStream (если двоичный), StringBufferInputStream (если строка) и т.д.

Ориентировочно эта логика:

InputStream fromHadoop = ...;         // 3rd paragraph 
Base64InputStream b64is =          // 2nd paragraph 
    new Base64InputStream(fromHadoop, false, 80, "\n".getBytes("UTF-8")); 
GZIPInputStream zis = new GZIPInputStream(b64is);    // 1st paragraph 

Пожалуйста, обратите внимание на аргументы Base64InputStream (длина строки и массив байтов в конце строки), вам может потребоваться их настройка.

+0

Спасибо большое, Никос. Класс Base64InputStream помог. –

0

Благодаря Nikos для указания меня в правильном направлении. В частности, это то, что я сделал:

private static final byte NEWLINE = (byte) '\n'; 
private static final byte CARRIAGE_RETURN = (byte) '\r'; 

byte[] lineSeparators = new byte[] {CARRIAGE_RETURN, NEWLINE};  
Base64InputStream b64is = new Base64InputStream(inputStream, false, 76, lineSeparators); 

GZIPInputStream zis = new GZIPInputStream(b64is); 

Не 76 длина линии Base64? Я не пытался с 80, однако.

+0

Если оно было зафиксировано на длине 76, то они не включили бы аргумент конструктора. Также подумайте о URI данных, где все это одна строка. – TWiStErRob

Смежные вопросы