2016-08-22 5 views
2

У меня есть много файлов PDF, которые мне нужно получить, чтобы его содержимое закодировано с помощью base64. У меня есть приложение Akka, которое извлекает файлы в виде потока и распределяет для многих работников для кодирования этих файлов и возвращает строку base64 для каждого файла. Я получил базовое решение для кодирования:Java-буферизированный base64-кодировщик для потоков

org.apache.commons.codec.binary.Base64InputStream; 
    ... 
    Base64InputStream b64IStream = null; 
    InputStreamReader reader = null; 
    BufferedReader br = null; 
    StringBuilder sb = new StringBuilder(); 
    try { 
     b64IStream = new Base64InputStream(input, true); 
     reader = new InputStreamReader(b64IStream); 
     br = new BufferedReader(reader); 
     String line; 
     while ((line = br.readLine()) != null) { 
      sb.append(line); 
     } 
    } finally { 
     if (b64IStream != null) { 
      b64IStream.close(); 
     } 
     if (reader != null) { 
      reader.close(); 
     } 
     if (br != null) { 
      br.close(); 
     } 
    } 

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

Я проверил некоторые другие подходы, такие как:

  • Base64.getEncoder
  • sun.misc.BASE64Encoder
  • Base64.encodeBase64
  • javax.xml.bind.DatatypeConverter.printBase64
  • com.google.guava.BaseEncoding.base64

Они быстрее, но им нужен весь файл, правильно? Кроме того, я не хочу блокировать другие потоки при кодировании 1 файла PDF.

Любой вход действительно полезен. Спасибо!

+0

Что значит «с буфером». Что будет вводить, и что вы ожидаете от вывода? Поток? Канал? Строка? – RealSkeptic

+0

Вход представляет собой InputStream, выход представляет собой содержимое строки base64. Буфером будет BufferedReader. –

ответ

3

Замечательный факт о Base64: он принимает три байта и преобразует их в четыре буквы. Это означает, что если вы читаете двоичные данные в кусках, которые делятся на три, вы можете кормить куски до любым кодировщиком Base64, и он будет кодировать его так же, как если бы вы отправили ему весь файл.

Теперь, если вы хотите, чтобы ваш выходной поток, чтобы быть просто одна длинная линия данных Base64 - что совершенно законно - то все, что вам нужно сделать, это что-то вдоль линий:

private static final int BUFFER_SIZE = 3 * 1024; 

try (BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);) { 
    Base64.Encoder encoder = Base64.getEncoder(); 
    StringBuilder result = new StringBuilder(); 
    byte[] chunk = new byte[BUFFER_SIZE]; 
    int len = 0; 
    while ((len = in.read(chunk)) == BUFFER_SIZE) { 
     result.append(encoder.encodeToString(chunk)); 
    } 
    if (len > 0) { 
     chunk = Arrays.copyOf(chunk,len); 
     result.append(encoder.encodeToString(chunk)); 
    } 
} 

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

Приведенный выше пример с Java 8 Base64, но вы действительно можете использовать любой кодировщик, который принимает байтовый массив произвольной длины и возвращает строку base64 этого байтового массива.

Это означает, что вы можете поиграть с размером буфера, как хотите.

Если вы хотите, чтобы ваш выход был совместимым с MIME, вам нужно разделить выходные данные на линии. В этом случае я бы установил размер куска в приведенном выше примере на то, что при умножении на 4/3 дает вам круглое количество строк. Например, если вы хотите иметь 64 символа в строке, каждая строка кодирует 64/4 * 3, что составляет 48 байт. Если вы кодируете 48 байтов, вы получите одну строку. Если вы кодируете 480 байтов, вы получите 10 полных строк.

Так измените приведенный выше BUFFER_SIZE на что-то вроде 4800. Вместо Base64.getEncoder() используйте Base64.getMimeEncoder(64,new byte[] { 13, 10}). И затем, когда он кодирует, вы получите 100 полноразмерных строк из каждого фрагмента, кроме последнего. Возможно, вам понадобится добавить result.append("\r\n") в цикл while.

+0

Большое спасибо! Мне просто нужно было переключить кодировщик, потому что я использую java 6. Перед этим изменением потребовалось ~ 900 мс для кодирования, теперь для одного и того же файла требуется 103 мс. –

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

  • Нет связанных вопросов^_^