2010-08-26 4 views
12

Ich habe eine Anforderung, wobei ich eine ZIP-Datei aus einer Liste verfügbarer Dateien erstellen muss. Die Dateien sind von verschiedenen Typen wie TXT, PDF, XML usw. Ich benutze Java-Util-Klassen, um es zu tun.So schätzen Sie die Größe der ZIP-Datei in Java vor dem Erstellen

Die Anforderung hier ist, eine maximale Dateigröße von 5 MB beizubehalten. Ich sollte die Dateien aus der Liste basierend auf Timestamp auswählen, fügen Sie die Dateien zu komprimieren, bis die ZIP-Dateigröße 5 MB erreicht. Ich sollte die restlichen Dateien überspringen.

Bitte lassen Sie mich wissen, wenn es einen Weg in Java gibt, wo ich die Größe der ZIP-Datei im Voraus schätzen kann, ohne die eigentliche Datei zu erstellen?

Oder gibt es einen anderen Ansatz, um dies

Antwort

0

ich es nicht behandeln denken, ist eine Möglichkeit, die Größe der Reißverschluss zu schätzen, die erstellt werden, weil die Reißverschlüsse als Streams verarbeitet werden. Außerdem ist es technisch nicht möglich, die Größe des erstellten komprimierten Formats vorherzusagen, es sei denn, Sie komprimieren es tatsächlich.

8

Wickeln Sie Ihren ZipOutputStream in einen personalisierten OutputStream, der hier YourOutputStream genannt wird.

  • Der Konstruktor von YourOutputStream wird eine weitere ZipOutputStream (zos2) schaffen, die eine neue ByteArrayOutputStream (baos) wickelt
    public YourOutputStream(ZipOutputStream zos, int maxSizeInBytes)
  • Wenn Sie eine Datei mit YourOutputStream schreiben wollen, wird es schreiben Sie es zuerst auf zos2
    public void writeFile(File file) throws ZipFileFullException
    public void writeFile(String path) throws ZipFileFullException
    etc ...
  • wenn baos.size() unterist
    • Schreiben Sie die Datei in zos1
  • sonst
    • schließen zos1, baos, zos2 eine Ausnahme ein Wurf. Für die Ausnahme kann ich nicht an eine bereits existierende denken, wenn es sie gibt, verwenden Sie sie, sonst erstellen Sie Ihre eigene IOException ZipFileFullException.

Sie benötigen zwei ZipOutputStream, ein auf dem Laufwerk geschrieben werden, ein zu überprüfen, ob Ihre Inhalte über 5 MB ist.

EDIT: In der Tat habe ich überprüft, you can't remove a ZipEntry easily.

http://download.oracle.com/javase/6/docs/api/java/io/ByteArrayOutputStream.html#size()

+0

Vielen Dank für Ihre Hilfe. Da ich nur eine grobe Größe brauche und in der Lage bin, für die meisten der von uns verwendeten Dateitypen das Komprimierungsverhältnis zu ermitteln, habe ich das von Nate vorgeschlagene Format verwendet. Danke alle noch einmal – Vignesh

0

habe ich dieses ein Mal an einem Projekt mit bekannten Eingabetypen. Wir wussten, dass unsere Daten allgemein um 5: 1 komprimiert waren (es war alles Text.) Also würde ich die Dateigröße überprüfen und durch 5 ...

teilen. In diesem Fall war der Zweck dafür Überprüfen Sie, ob Dateien unter einer bestimmten Größe liegen. Wir brauchten nur eine grobe Schätzung.

Alles, was ich gesagt habe, habe ich bemerkt Zip-Anwendungen wie 7zip wird eine Zip-Datei einer bestimmten Größe (wie eine CD) erstellen und dann die Zip-Off in eine neue Datei, sobald es das Limit erreicht. Sie könnten diesen Quellcode ansehen.Ich habe tatsächlich die Befehlszeilenversion dieser App im Code zuvor verwendet. Sie haben eine Bibliothek, die Sie auch verwenden können. Nicht sicher, wie gut das in Java integriert wird.

Für was es wert ist, habe ich auch eine Bibliothek namens SharpZipLib verwendet. Es war sehr gut. Ich frage mich, ob es einen Java-Port gibt.

1

+1 für Colin Herbert: Fügen Sie Dateien einzeln hinzu, entweder sichern Sie den vorherigen Schritt oder entfernen Sie die letzte Datei, wenn das Archiv zu groß ist. Ich möchte nur einige Details hinzufügen:

Vorhersage ist viel zu unzuverlässig. Zum Beispiel Ein PDF-Dokument kann unkomprimierten Text enthalten und bis zu 30% des Originals komprimieren, oder es enthält bereits komprimierten Text und Bilder, die auf 80% komprimiert werden. Sie müssten die gesamte PDF-Datei auf Komprimierbarkeit prüfen und sie im Wesentlichen komprimieren.

Sie könnten versuchen, eine statistische Vorhersage, aber das könnte die Anzahl der fehlgeschlagenen Versuche reduzieren, aber Sie müssten immer noch oben genannten Empfehlung implementieren. Gehen Sie zuerst mit der einfacheren Implementierung und sehen Sie, ob es genug ist.

Alternativ können Sie die Dateien einzeln komprimieren, dann wählen Sie die Dateien aus, die zusammen 5 MB nicht überschreiten. Wenn das Entpacken ebenfalls automatisiert ist, können Sie die Zip-Dateien in eine einzige unkomprimierte Zip-Datei binden.

+0

Wenn dies nicht wirklich funktioniert, könnten Sie eine Datei über 5MB haben, die nur "aaaa ..." enthält, sie wäre komprimiert genug, um in die Zip zu passen. –

+0

d'oh. Darf ich frühmorgendliche Dummheit beanspruchen? – peterchen

+0

(behoben, natürlich) – peterchen

1

Vielleicht könnten Sie jedes Mal eine Datei hinzufügen, bis Sie die Grenze von 5 MB erreichen, und dann die letzte Datei verwerfen. Wie @Gopi, ich glaube nicht, dass es eine Möglichkeit gibt, es zu schätzen, ohne die Datei tatsächlich zu komprimieren.

Natürlich wird die Dateigröße nicht (oder vielleicht ein wenig, wegen der Zip-Header?), So dass Sie zumindest eine "Worst-Case" -Einschätzung haben.

+0

Siehe "Maximaler Expansionsfaktor" unter http://zlib.net/zlib_tech.html – snemarch

0

wollte nur teilen, wie wir manuelle Art und Weise

  int maxSizeForAllFiles = 70000; // Read from property 
     int sizePerFile = 22000; // Red from property 
     /** 
     * Iterate all attachment list to verify if ZIP is required 
     */ 
     for (String attachFile : inputAttachmentList) { 
      File file = new File(attachFile); 
      totalFileSize += file.length(); 
      /** 
      * if ZIP required ??? based on the size 
      */ 
      if (file.length() >= sizePerFile) { 
       toBeZipped = true; 
       logger.info("File: " 
          + attachFile 
           + " Size: " 
           + file.length() 
           + " File required to be zipped, MAX allowed per file: " 
           + sizePerFile); 
       break; 
      } 
     } 
     /** 
     * Check if all attachments put together cross MAX_SIZE_FOR_ALL_FILES 
     */ 
     if (totalFileSize >= maxSizeForAllFiles) { 
      toBeZipped = true; 
     } 
     if (toBeZipped) { 
      // Zip Here iterating all attachments 
     } 
0

Es ist eine bessere Option implementiert. Erstellen Sie eine Dummy-LengthOutputStream, die gerade zählt die geschriebenen Bytes:

public class LengthOutputStream extends OutputStream { 

    private long length = 0L; 

    @Override 
    public void write(int b) throws IOException { 
     length++; 
    } 

    public long getLength() { 
     return length; 
    } 
} 

Sie können einfach nur verbinden die LengthOutputStream zu einem ZipOutputStream:

public static long sizeOfZippedDirectory(File dir) throws FileNotFoundException, IOException { 
     try (LengthOutputStream sos = new LengthOutputStream(); 
      ZipOutputStream zos = new ZipOutputStream(sos);) { 
      ... // Add ZIP entries to the stream 
      return sos.getLength(); 
     } 
    } 

Das LengthOutputStream Objekt zählt die Bytes des RV-Stream speichert aber nichts, Es gibt also keine Dateigröße. Diese Methode liefert eine genaue Größenschätzung, ist aber fast so langsam wie das Erstellen einer ZIP-Datei.

Verwandte Themen