1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

Einer Zip Datei ein leeres Verz. hinzufügen

Dieses Thema im Forum "Java" wurde erstellt von DarthShader, 16. März 2007.

  1. DarthShader

    DarthShader Erfahrenes Mitglied

    Hallo,

    ich habe z.Z. ein kleines Problem, was das handling von Zip-Files in Java angeht. Ich kann sehr leicht ein Zip File erstellen und Dateien hinzufügen (Stichwort ZipOutputStream, ZipEntry etc...).

    Aber: ich würde dem Zip File gerne ein Verzeichnis hinzufügen, und zwar ein leeres.

    Ich habe das Gefühl, dass die ZipEntrys nur Dateien sein können. Ich hoffe, dass ich damit nicht recht habe.

    Kann mir jemand helfen?


    Danke!
  2. Moin!
    So gehts:
    Code (Text):
    1.  
    2. ZipOutputStream zout = new ZipOutputStream(new FileOutputStream("F:/test.zip"));
    3.             ZipEntry e = new ZipEntry("Test/");
    4.             zout.putNextEntry(e);
    5.             zout.closeEntry();
    6.             zout.close();
    7.  

    *grüssle*
    MeinerEiner
  3. Thomas Darimont

    Thomas Darimont Administrator

    Hallo,

    nein du kannst auch (leere) Verzeichnisse zippen. Das Problem dabei ist nur, dass einige Packprogramme wie WinZip scheinbar nicht richtige mit leeren Verzeichnissen umgehen können... (sprich der leere Ordner ist im Zip wird aber nicht angezeigt)

    Gruß Tom
  4. DasArne

    DasArne Grünschnabel

    Hallo zusammen,
    ich muss dieses Thema nochmal aufgreifen.
    Die meisten legen für Ordner erst gar keine ZipEntries an, und fahren damit sicher mit den meisten Zip-Programmen gut. Ich möchte aber Zip-Folder kommentieren. Das Kommandozeilentool zip kann das mit der Option -c also geht das prinzipiell.
    Ich versuche das folgender maßen:
    Code (Text):
    1.  
    2. package org.example.zip;
    3.  
    4. import java.io.BufferedOutputStream;
    5. import java.io.FileOutputStream;
    6.  
    7. import org.apache.tools.zip.ZipEntry;
    8. import org.apache.tools.zip.ZipOutputStream;
    9.  
    10. public class ZipTest {
    11.         public static void main (String argv[]) {
    12.                 try {
    13.                         FileOutputStream dest = new FileOutputStream("/tmp/checkFolder.zip");
    14.                         ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
    15.  
    16.                         ZipEntry folderEntry = new ZipEntry("TestFolder");
    17.                         folderEntry.setComment("My Folder comment.");
    18.                         out.putNextEntry(folderEntry);
    19.                         out.closeEntry();
    20.                        
    21.                         ZipEntry fileEntry = new ZipEntry("TestFolder/TestFile.txt");
    22.                         fileEntry.setComment("My File comment.");
    23.                         out.putNextEntry(fileEntry);
    24.                         out.write("Hallo Zip!".getBytes());
    25.                         out.closeEntry();
    26.                        
    27.                         out.close();
    28.                 } catch(Exception e) {
    29.                         e.printStackTrace();
    30.                 }
    31.         }
    32. }
    33.  
    Wenn ich mir das mit unzip anschaue sieht das zuerst gut aus:
    Code (Text):
    1. Archive:  /tmp/checkFolder.zip
    2.   Length     Date   Time    Name
    3.  --------    ----   ----    ----
    4.         0  09-22-09 15:09   TestFolder
    5. My Folder comment.
    6.        10  09-22-09 15:09   TestFolder/TestFile.txt
    7. My File comment.
    8.  --------                   -------
    9.        10                   2 files
    10.  
    Das mit Windows ausgeliefert "eingebaute" Zip findet leider immer leere Dateien mit dem Namen des Ordners und unzip hat natürlich ein Problem sowas auszupacken:
    Code (Text):
    1. unzip  /tmp/checkFolder.zip                                                      
    2. Archive:  /tmp/checkFolder.zip                                                                      
    3.   inflating: TestFolder                                                                              
    4. checkdir error:  TestFolder exists but is not directory                                              
    5.                  unable to process TestFolder/TestFile.txt.    
    6.  
    Kann man nicht doch irgendwie einem ZipEntry sagen, das es ein Verzeichnis ist?
    Wie kann man ein Verzeichnis mit Kommentar anlegen?

    Viele Grüße
    Arne

    Anhänge:

  5. Thomas Darimont

    Thomas Darimont Administrator

    Hallo,

    wenn ich mir hiermit mal ein Zip File generieren lasse und mir anschließend das Zip mit der Windows Zip Unterstützung anschaue, sehe ich

    "test1" als Datei
    "test2" als Ordner und darin die Datei "test3".

    Wenn ich dieses zip jedoch entpacke bekomme ich korrekte Verzeichnisse angelegt.

    Deshalb die Frage: Ist es wirklich so schlimm, wenn du mit der Windows Zip Unterstützung die Verzeichnisse nicht richtig siehst? Schließlich sind sie ja da wenn man das zip entpackt.

    Code (Java):
    1.  
    2. public class ZipWithEmtpyDirectoriesExample {
    3.  
    4.     /**
    5.      * @param args
    6.      */
    7.     public static void main(String[] args) throws Exception{
    8.         ZipOutputStream zip = new ZipOutputStream(new FileOutputStream("/tmp/zipWithEmptyFolders.zip"));
    9.         zip.putNextEntry(new ZipEntry("test1/"));
    10.         zip.putNextEntry(new ZipEntry("test2/test3/"));
    11.         zip.closeEntry();
    12.         zip.close();
    13.     }
    14.  
    15. }
    16.  
    Gruß Tom

    Anhänge:

  6. DasArne

    DasArne Grünschnabel

    Hi Tom,
    danke Dir für Deine Antwort. Natürlich ist es kein Beinbruch wenn mir ein Windows-Zip ein Verzeichnis und eine Datei mit dem selben Namen anzeigt. Bis auf das Kommando-Zeilentool unzip scheinen sowieso alle zip-Programme sich sehr viel Mühe zu geben ohne Fehlermeldungen zip-Files auszupacken.
    Aber das ZipEntry hat ja immerhin die Methode isDirectory() . Und das nicht ohne Grund: Das auspackende Programm muss da einen Ordner anlegen. Wie wird dieser Boolean bestimmt? Ist ein leerer Eintrag immer ein Folder? Wo ist der Setter? :)
    Ich habe die apache-zip-utils aus dem ant.jar genommen, weil man damit das Encoding für Dateinamen und Kommentare setzen kann. (Kann ich nur jedem ans Herz legen. Achtung unterschiedlich Encoding für unterschiedliche Plattformen: Windows braucht "Cp437" der Rest der Welt "UTF-8")
    Im Java-Doc vom ZipOutputStream steht dazu:
    Könnten dieses isDirectory nicht ein "especially internal/external file attributes" sein? ;)
    Leider wird im Weiteren nicht mehr darauf eingegangen?
    Tom hast Du schon mal was mit diesen "file attributes" gemacht?
    Weißt Du was die meinen?

    Viele Grüße
    Arne
  7. Thomas Darimont

    Thomas Darimont Administrator

    Hallo,

    In der Apache Ant Variante von ZipEntry ist die isDirectory Methode folgendermaßen implementiert:
    Code (Java):
    1.  
    2.   public boolean isDirectory()
    3.   {
    4.     return getName().endsWith("/");
    5.   }
    6.  
    ... also nicht als "Special Attribut" sondern eher als eine Namenskonvention.


    Gruß Tom
  8. DasArne

    DasArne Grünschnabel

    Hi Thomas,
    ja, ein scharfer Blick in den Source kann ja Berge versetzen. ;) Danke Dir Thomas! :)
    Unzip lässt sich mit mit Deinem Tipp tatsächlich dazu überreden das Zip-File auszupacken.
    Mein gewünschtes explizites Setzen der Art eines ZipEntries, kann (und muss - meiner Meinung nach) dennoch durchgeführt werden.
    Man muss das 4. Bit der External-Atrributes setzen! Ist dieses Bit an, ist es ein Verzeichnis, ist es aus, handelt es sich um eine Datei.
    Hier nochmal das komplette Beispiel zum Mitschreiben:
    Code (Java):
    1.  
    2. package org.example;
    3.  
    4. import java.io.BufferedOutputStream;
    5. import java.io.FileOutputStream;
    6.  
    7. import org.apache.tools.zip.ZipEntry;
    8. import org.apache.tools.zip.ZipOutputStream;
    9.  
    10. public class ZipTest {
    11.  
    12.     public final static long ZIPENTRY_IS_DIRECTORY = 1<<4;
    13.     public final static String WINDOW_ZIP_ENCODING="Cp437";
    14.     public final static String NON_WINDOW_ZIP_ENCODING="UTF-8";
    15.    
    16.     public static void main (String argv[]) {
    17.         try {
    18.             // Bitmask indicating directories in 'external attributes' of a ZIP archive entry.
    19.  
    20.             FileOutputStream dest = new FileOutputStream("/tmp/checkFolder.zip");
    21.             ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
    22.             out.setEncoding(WINDOW_ZIP_ENCODING);
    23.            
    24.             ZipEntry folderEntry = new ZipEntry("TestFolder/");
    25.             folderEntry.setExternalAttributes(folderEntry.getExternalAttributes()|ZIPENTRY_IS_DIRECTORY);
    26.             folderEntry.setComment("My Folder comment.");
    27.             out.putNextEntry(folderEntry);
    28.             out.closeEntry();
    29.            
    30.             ZipEntry fileEntry = new ZipEntry("TestFolder/TestFile.txt");
    31.             fileEntry.setComment("My File comment.");
    32.             out.putNextEntry(fileEntry);
    33.             out.write("Hallo Zip!".getBytes());
    34.             out.closeEntry();
    35.            
    36.             out.close();
    37.         } catch(Exception e) {
    38.             e.printStackTrace();
    39.         }
    40.     }
    41. }
    42.  
    Nun kann auch Windows-Zip was damit anfangen.
    Alternativ kann man auch sinniger Weise den Unixmode setzen. (!) Der rechnet nämlich ganz neben bei ein komplettes ExternalAttribute zusammen.
    Natürlich für Verzeichnisse nur richtig, wenn Dein Slash am Ende des Verzeichnis-Namens steht. :)
    Code (Java):
    1.  
    2.     public void setUnixMode(int mode) {
    3.         setExternalAttributes((mode << 16)
    4.                               // MS-DOS read-only attribute
    5.                               | ((mode & 0200) == 0 ? 1 : 0)
    6.                               // MS-DOS directory flag
    7.                               | (isDirectory() ? 0x10 : 0));
    8.         platform = PLATFORM_UNIX;
    9.     }
    10.  
    Das sollte dann zu allen möglichen Plattformen kompatible sein.

    Viele Grüße
    Arne
    Zuletzt bearbeitet: 24. September 2009
  9. Thomas Darimont

    Thomas Darimont Administrator

    Hallo,

    coole Sache, danke für den Tipp :)

    Gruß Tom

Diese Seite empfehlen