Base64-кодировать файл и сжать его
-
13-12-2019 - |
Вопрос
Моя цель — закодировать файл и заархивировать его в папке в Java.Мне нужно использовать библиотеку кодеков Apache Commons.Я могу закодировать и заархивировать его, и он работает нормально, но когда я декодирую его обратно в исходную форму, похоже, что файл не полностью закодирован.Похоже, не хватает нескольких деталей.Может ли кто-нибудь сказать мне, почему это происходит?
Я также прилагаю часть своего кода для справки, чтобы вы могли помочь мне соответствующим образом.
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();
}
}
Решение
Данные в кодировке BASE64 обычно длиннее исходных, однако вы используете длину исходных данных для записи закодированных данных в выходной поток.
Вы используете размер сгенерированного массива вместо вашей переменной. len
.
Второе уведомление – не переопределять buffer
каждый раз, когда вы кодируете байт.Просто запишите результат в вывод.
while ((len = in.read(buffer)) > 0) {
byte [] enc = Base64.encodeBase64(Arrays.copyOf(buffer, len));
out.write(enc, 0, enc.length);
}
ОБНОВЛЯТЬ:Использовать Массивы.copyOf(...) установить длину входного буфера для кодирования.
Другие советы
Ваша главная проблема заключается в том, что кодировка Base64 не может быть приложена к блокам (особенно не реализация Apache-Commons).Эта проблема ухудшается, потому что вы даже не знаете, насколько большими его блоки являются, так как это зависит от байтов, прочитанных in.read(..)
.
Поэтому у вас есть две альтернативы:
- Загрузите полный файл в память, а затем примените кодировку Base64.
- Используйте альтернативную реализацию энкодера Base64, которая работает на основе потока (проект Apache Batik, по-видимому, содержит такую реализацию: org.apache.batik.util.base64EncoderStream )
Когда вы читаете содержимое файла в буфер , вы получаете len bytes.Когда BASE64 кодирует это, вы получаете больше, чем Len Bytes, но вы все равно только пишу Len Bytes в файл.Эта фасоль, что последняя часть ваших чтения будет усечена.
Кроме того, если ваш читал не заполняет весь буфер, вы не должны Base64 кодировать больше, чем Len Bytes, поскольку вы в противном случае получите трейлинг 0s в заполнении последних байтов.
Объединение информации выше этого означает, что вы должны Base64 кодировать весь файл (прочитайте все в байте []), если вы не можете гарантировать, что каждый кусок, который вы читаете, могут вписаться именно в кодированное сообщение Base64.Если ваши файлы не очень большие, я бы порекомендовал прочитать весь файл.
Меньшая проблема в том, что при чтении в вашем цикле вы, вероятно, должны проверить «> -1», а не «> 0», но int его случай это не имеет значения.