Base64-кодирует файл и сжимает его - PullRequest
5 голосов
/ 13 марта 2012

Моя цель - закодировать файл и заархивировать его в папку в java.Я должен использовать библиотеку Apache's Commons-codec.Я могу закодировать и заархивировать его, и он работает нормально, но когда я декодирую его обратно в исходную форму, похоже, что файл не был полностью закодирован.Похоже, некоторые части отсутствуют.Кто-нибудь может сказать мне, почему это происходит?

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

private void zip() {
    int BUFFER_SIZE = 4096;
    byte[] buffer = new byte[BUFFER_SIZE];

    try {
        // Create the ZIP file
        String outFilename = "H:\\OUTPUT.zip";
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
                outFilename));

        // Compress the files
        for (int i : list.getSelectedIndices()) {
            System.out.println(vector.elementAt(i));
            FileInputStream in = new FileInputStream(vector.elementAt(i));
            File f = vector.elementAt(i);

            // Add ZIP entry to output stream.
            out.putNextEntry(new ZipEntry(f.getName()));

            // Transfer bytes from the file to the ZIP file
            int len;

            while ((len = in.read(buffer)) > 0) {
                buffer = org.apache.commons.codec.binary.Base64
                        .encodeBase64(buffer);
                out.write(buffer, 0, len);

            }

            // Complete the entry
            out.closeEntry();
            in.close();

        }

        // Complete the ZIP file
        out.close();
    } catch (IOException e) {
        System.out.println("caught exception");
        e.printStackTrace();
    }
}

Ответы [ 3 ]

3 голосов
/ 13 марта 2012

BASE64-кодированные данные обычно длиннее исходных, однако вы используете длину исходных данных для записи закодированных в выходной поток.

Вы используете размер сгенерированного массива вместо вашей переменной len.

Второе уведомление - не переопределяйте buffer каждый раз, когда вы кодируете байт. Просто запишите результат в вывод.

 while ((len = in.read(buffer)) > 0)  {                         
     byte [] enc = Base64.encodeBase64(Arrays.copyOf(buffer, len));
     out.write(enc, 0, enc.length);
 }

ОБНОВЛЕНИЕ: Используйте Arrays.copyOf (...) , чтобы установить длину входного буфера для кодирования.

0 голосов
/ 13 марта 2012

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

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

Объединение вышеприведенной информации означает, что вы должны кодировать base64 весь файл (прочитайте все это в байт []), если только вы не можете гарантировать, что каждый прочитанный вами блок может вписаться точно в сообщение, закодированное в base64. Если ваши файлы не очень большие, я бы рекомендовал прочитать весь файл.

Меньшая проблема заключается в том, что при чтении в вашем цикле вы, вероятно, должны проверять наличие «> -1», а не «> 0», но в его случае это не имеет значения.

0 голосов
/ 13 марта 2012

Ваша основная проблема заключается в том, что кодировка base64 не может применяться блочно (особенно в реализации apache-commons).Эта проблема усугубляется тем, что вы даже не знаете, насколько велики ваши блоки, поскольку это зависит от байтов, прочитанных in.read(..).

Поэтому у вас есть две альтернативы:

  1. Загрузите весь файл в память и затем примените кодировку base64.
  2. используйте альтернативную реализацию кодера Base64, которая работает на основе потоков (проект Apache Batik, по-видимому, содержит такую ​​реализацию: org.apache.batik.util.Base64EncoderStream )
...