Base64-kodieren Sie eine Datei und komprimieren Sie sie
-
13-12-2019 - |
Frage
Mein Ziel ist es, eine Datei zu codieren und in einen Ordner in Java zu komprimieren.Ich muss die Commons-Codec-Bibliothek des Apache verwenden.Ich kann es codieren und komprimieren und es funktioniert einwandfrei, aber wenn ich es wieder in seine ursprüngliche Form dekodiere, sieht es so aus, als ob die Datei nicht vollständig codiert wurde.Sieht so aus, als ob ein paar Teile fehlen.Kann mir jemand sagen, warum das passiert?
Ich füge auch den Teil meines Codes als Referenz bei, damit Sie mich entsprechend führen können.
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();
}
}
Lösung
BASE64-codierte Daten sind normalerweise länger als die Quelle, Sie verwenden jedoch die Länge der Quelldaten, um codiert in den Ausgabestream zu schreiben.
Sie haben die Größe des generierten Arrays anstelle Ihrer Variablen verwendet len
.
Zweiter Hinweis - nicht neu definieren buffer
jedes Mal, wenn Sie ein Byte codieren.Schreiben Sie einfach das Ergebnis in die Ausgabe.
while ((len = in.read(buffer)) > 0) {
byte [] enc = Base64.encodeBase64(Arrays.copyOf(buffer, len));
out.write(enc, 0, enc.length);
}
UPDATE:Verwenden Array.Kopie von(...) um die Länge des Eingabepuffers für die Codierung festzulegen.
Andere Tipps
Ihr Hauptproblem ist, dass die Base64-Codierung nicht blockweise angewendet werden kann (insbesondere nicht die Apache-Commons-Implementierung).Dieses Problem wird immer schlimmer, weil Sie nicht einmal wissen, wie groß Ihre Blöcke sind, da dies von den gelesenen Bytes abhängt in.read(..)
.
Daher haben Sie zwei Alternativen:
- Laden Sie die vollständige Datei in den Speicher und wenden Sie dann die Base64-Codierung an.
- verwenden Sie eine alternative Base64-Encoder-Implementierung, die Stream-basiert funktioniert (das Apache Batik-Projekt scheint eine solche Implementierung zu enthalten: Organisierungstafel.Apache.Batik.util.Base64EncoderStream)
Wenn Sie den Dateiinhalt in puffer lesen, erhalten Sie len bytes.Wenn Base64 codiert, erhalten Sie mehr als len bytes, aber Sie schreiben immer noch nur len bytes in die Datei.Diese Bohnen, die der letzte Teil Ihrer gelesenen Brocken abgeschnitten wird.
, wenn Ihr Lese auch den gesamten Puffer nicht füllt, sollten Sie nicht base64 codieren als len Bytes, da Sie andernfalls 0s in der Polsterung der letzten Bytes zurücklegen werden.
Die Kombination der Informationen darüber bedeutet, dass Sie base64 codieren müssen.Wenn Ihre Dateien nicht sehr groß sind, würde ich empfehlen, die gesamte Datei zu lesen.
Ein kleineres Problem ist, dass Sie beim Lesen in Ihrer Schleife wahrscheinlich für "> -1", nicht "> 0", prüfen sollten, aber int int seinen Fall, jedoch keinen Unterschied.