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.
ZipEntry class is used to represent a ZIP file entry.
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.
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.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With