Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8303925

ZipOutStream::putEntry should include an apiNote to indicate that the STORED compression method should be used when writing directory entries

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 21
    • core-libs
    • None
    • behavioral
    • minimal
    • There is no change in the default behavior of ZipOutputStream, the apiNote simply adds a recommendation of which compression method to use for directory entries
    • Java API
    • SE

      Summary

      Add an @apiNote to ZipOutputStream.putNextEntry recommending that directory entries should be added using the STORED compression method.

      Problem

      ZipOutputStream defaults to writing entries using the DEFLATE compression method which is most likely due to the following APPNOTE.txt section:

      4.1.3 Data compression MAY be used to reduce the size of files
         placed into a ZIP file, but is not required.  This format supports the 
         use of multiple data compression algorithms.  When compression is used, 
         one of the documented compression algorithms MUST be used.  Implementors 
         are advised to experiment with their data to determine which of the 
         available algorithms provides the best compression for their needs.
         Compression method 8 (Deflate) is the method used by default by most 
         ZIP compatible application programs

      .

      The use of DEFLATE compression method when writing directory entries results in file data containing a two-byte 'final empty' DEFLATE block being written, followed by a 16-byte data descriptor.

      The following APPNOTE.txt supports the use of the STORED compression method for directory entries:

      4.3.8 File data

        Immediately following the local header for a file
        SHOULD be placed the compressed or stored data for the file.
        If the file is encrypted, the encryption header for the file 
        SHOULD be placed after the local header and before the file 
        data. The series of [local file header][encryption header]
        [file data][data descriptor] repeats for each file in the 
        .ZIP archive. 
      
        Zero-byte files, directories, and other file types that 
        contain no content MUST NOT include file data.

      Additionally, benchmarks show that the writing of these empty DEFLATED directory entries are ~10X slower compared to an empty STORED entry.

      Note: the jar command specifies the STORED compression method when creating directory entries.

      Solution

      Add an @apiNote to ZipOutputStream.putNextEntry recommending the use of the STORED compression method for directory entries. The note should include a snippet which shows the recommended configuration of a directory ZipEntry.

      (As an alternative solution, putNextEntry could be updated to change the default compression method to STORED for directory entires. This was deemed as having a too high risk, since users may be depending of the ability to attach arbitrary data to directory entries.)

      Specification

      Add the following @apiNote to ZipOutputStream.putNextEntry:

          diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java
      --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java    (revision f2b03f9a2c0fca853211e41a1ddf46195dd56698)
      +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java    (revision 24d2afc265abaeff928f7a6e8a5557fe371ee8d6)
      @@ -191,6 +191,21 @@
            * <p>
            * The current time will be used if the entry has no set modification time.
            *
      +     * @apiNote When writing a directory entry, the STORED compression method
      +     * should be used and the size and CRC-32 values should be set to 0:
      +     *
      +     * {@snippet lang = "java":
      +     *     ZipEntry e = new ZipEntry(entryName);
      +     *     if (e.isDirectory()) {
      +     *         e.setMethod(ZipEntry.STORED);
      +     *         e.setSize(0);
      +     *         e.setCrc(0);
      +     *     }
      +     *     stream.putNextEntry(e);
      +     *}
      +     *
      +     * This allows optimal performance when processing directory entries.
      +     *
            * @param     e the ZIP entry to be written
            * @throws    ZipException if a ZIP format error has occurred
            * @throws    IOException if an I/O error has occurred

            eirbjo Eirik Bjørsnøs
            lancea Lance Andersen
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: