Base64-кодирует файл и сжимает его
Моя цель состоит в том, чтобы закодировать файл и заархивировать его в папку в 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 ответа
Данные, закодированные в 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(...), чтобы установить длину входного буфера для кодирования.
Ваша основная проблема заключается в том, что кодирование base64 не может применяться блочно (особенно в реализации apache-commons). Эта проблема усугубляется, потому что вы даже не знаете, насколько велики ваши блоки, так как это зависит от байтов, прочитанных in.read(..)
,
Поэтому у вас есть две альтернативы:
- Загрузите полный файл в память и примените кодировку base64.
- использовать альтернативную реализацию кодера Base64, которая работает на основе потоков (проект Apache Batik, по-видимому, содержит такую реализацию: org.apache.batik.util.Base64EncoderStream)
Когда вы читаете содержимое файла в буфер, вы получаете len байтов. При кодировании base64 вы получаете больше, чем len байтов, но вы по-прежнему записываете в файл только len байтов. Это бобы, которые последняя часть ваших прочитанных кусков будет усечена.
Кроме того, если ваше чтение не заполняет весь буфер, вы не должны base64 кодировать больше, чем len байтов, так как в противном случае вы получите конечные 0 в заполнении последних байтов.
Объединение вышеприведенной информации означает, что вы должны кодировать base64 весь файл (считывать все это в байт []), если вы не можете гарантировать, что каждый прочитанный фрагмент может вписаться точно в сообщение, закодированное в base64. Если ваши файлы не очень большие, я бы рекомендовал прочитать весь файл.
Меньшая проблема заключается в том, что при чтении в вашем цикле вы, вероятно, должны проверять "> -1", а не "> 0", но в его случае это не имеет значения.