Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java NIO Zip Filesystem equivalent of setMethod() in java.util.zip.ZipEntry

I have some existing code to create zip files in the Epub 2 format, which works correctly.

In trying to update my code to support the Epub 3 format, I thought I would try the Java NIO Zip Filesystem instead of java.util.zip.ZipFile. I am almost there except for one tiny item.

There is a 20 byte mimetype file required by the Epub format which must be put into the zip in uncompressed form. The java.util.zip.ZipEntry api provides setMethod(ZipEntry.STORED) to achieve this.

I cannot find any reference to this in the Java NIO FileSystem API doc. Is there an equivalent of ZipEntry.setMethod() ?

EDIT 1

OK, so I see how to display the attributes, and thank you for that example, but I can't find any doc on how to create an attribute such as (zip:method,0), even on Oracle's own oracle. The NIO enhancements in Java 7 seem to me to have been only about 20% documented. The attributes api doc is very sparse, especially how to create attributes.

The feeling I am starting to get is that the NIO Zip filesystem may not be an improvement on java.util.zip, and requires more code to achieve the same result.

EDIT 2

I tried the following:

String contents = "application/epub+zip"; /* contents of mimetype file */
Map<String, String> map = new HashMap<>();
map.put("create", "true");

Path zipPath = Paths.get("zipfstest.zip");
Files.deleteIfExists(zipPath);

URI fileUri = zipPath.toUri(); // here
URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);

try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, map)) {
    Path pathInZip = zipfs.getPath("mimetype");
    Files.createFile(pathInZip, new ZipFileAttribute<Integer>("zip:method", 0));
    byte[] bytes = contents.getBytes();
    Files.write(pathInZip, bytes, StandardOpenOption.WRITE);
    }

The ZipFileAttribute class is a minimal implementation of the Attribute Interface. I can post it but it's just a key-value pair (name, value)

This code created the zipFile successfully, but when I open the zipFile with 7zip, I see that the mimetype file was stored in the zip as DEFLATED (8) rather than what I need which is STORED (0). So question is, how do I code the attribute correctly so it stores as STORED.

like image 580
casgage Avatar asked Jan 30 '15 15:01

casgage


People also ask

What is ZipEntry in Java?

ZipEntry class is used to represent a ZIP file entry.

How do I get files from ZipEntry?

To read the file represented by a ZipEntry you can obtain an InputStream from the ZipFile like this: ZipEntry zipEntry = zipFile. getEntry("dir/subdir/file1.

How can I read the content of a Zip file without unzipping it in Java?

Methods. getComment(): String – returns the zip file comment, or null if none. getEntry(String name): ZipEntry – returns the zip file entry for the specified name, or null if not found. getInputStream(ZipEntry entry) : InputStream – Returns an input stream for reading the contents of the specified zip file entry.

What is zip file system?

The zip file system provider treats a zip or JAR file as a file system and provides the ability to manipulate the contents of the file. The zip file system provider creates multiple file systems — one file system for each zip or JAR file.


1 Answers

This is not very well documented but the zip filesystem provider of the JDK supports a FileAttributeView by the name zip.

Here is the code from a zip of mine:

public static void main(final String... args)
    throws IOException
{
    final Path zip = Paths.get("/home/fge/t.zip");
    final Map<String, ?> env = Collections.singletonMap("readonly", "true");
    final URI uri = URI.create("jar:" + zip.toUri());

    try (
        final FileSystem fs = FileSystems.newFileSystem(uri, env);
    ) {
        final Path slash = fs.getPath("/");
        Files.readAttributes(slash, "zip:*").forEach( (key, val) -> {
            System.out.println("Attribute name: " + key);
            System.out.printf("Value: %s (class: %s)\n", val,
                val != null ? val.getClass(): "N/A");
        });
    }
}

Output:

Attribute name: size
Value: 0 (class: class java.lang.Long)
Attribute name: creationTime
Value: null (class: N/A)
Attribute name: lastAccessTime
Value: null (class: N/A)
Attribute name: lastModifiedTime
Value: 1969-12-31T23:59:59.999Z (class: class java.nio.file.attribute.FileTime)
Attribute name: isDirectory
Value: true (class: class java.lang.Boolean)
Attribute name: isRegularFile
Value: false (class: class java.lang.Boolean)
Attribute name: isSymbolicLink
Value: false (class: class java.lang.Boolean)
Attribute name: isOther
Value: false (class: class java.lang.Boolean)
Attribute name: fileKey
Value: null (class: N/A)
Attribute name: compressedSize
Value: 0 (class: class java.lang.Long)
Attribute name: crc
Value: 0 (class: class java.lang.Long)
Attribute name: method
Value: 0 (class: class java.lang.Integer)

It looks like the "zip:method" attribute is what you want.

So, if you want to change the method, if you have a Path into your zip filesystem, it looks like you can do (UNTESTED!):

Files.setAttribute(thePath, "zip:method", ZipEntry.DEFLATED);
like image 181
fge Avatar answered Oct 26 '22 12:10

fge