Java NIO ZipFileSystem: “zip END header not found”

2020-06-22 07:56发布

问题:

I'm asking this here because googling this error only gives me hits on writing a zip file, while I'm only trying to read it.
I have a unit test where I'm trying to test the following production code:

Map<String, String> zipProps = new HashMap<>();
URI zipUri = URI.create("jar:file:" + itemZipPath.toString());
try (FileSystem zipfiles = FileSystems.newFileSystem(zipUri, zipProps)) {
   // do stuff...
} catch (IOException e) {
   // log an error
}

However this fails on the line containing the try:

java.util.zip.ZipError: zip END header not found
at com.sun.nio.zipfs.ZipFileSystem.zerror(ZipFileSystem.java:1605)
at com.sun.nio.zipfs.ZipFileSystem.findEND(ZipFileSystem.java:1021)
at com.sun.nio.zipfs.ZipFileSystem.initCEN(ZipFileSystem.java:1030)
at com.sun.nio.zipfs.ZipFileSystem.<init>(ZipFileSystem.java:130)
at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:117)
at java.nio.file.FileSystems.newFileSystem(FileSystems.java:326)
at java.nio.file.FileSystems.newFileSystem(FileSystems.java:276)
at com.company.PageCommandHandler$ProvisioningSteps.getItemModel(PageCommandHandler.java:105)

I've tried creating the zipfile using both OSX's zip utility and using jar cvf but both fail (the output of file <filename> differs slightly however). All the information about this error I can find relates to creating a zipfile using Java NIO, but as you can see I'm only doing a read (verifying the presence of a certain file inside the ZIP for now). Any thoughts on what is going wrong here?

回答1:

I've met exactly the same error. Java 8. The reason was, by mistake I created an empty file, not only object:

File zipFile = new File(path);
zipFile.createNewFile();

An then passed this path to

URI uri = URI.create("jar:file:" + zipFile.getAbsolutePath());

To fix it, I did not create file itself, only created a File object:

File zipFile = new File(path);
URI uri = URI.create("jar:file:" + zipFile.getAbsolutePath());

To make it more reliable I would offer to delete file first if it exists:

File zipFile = new File(path);
//Caused by: java.util.zip.ZipError: zip END header not found
if (zipFile.exists()){
    try {
        Files.delete(Paths.get(zipFile.getAbsolutePath()));
    } catch (IOException e) {
        throw new IllegalStateException(
                "Could not delete file.", e);
    }
}
...
URI uri = URI.create("jar:file:" + zipFile.getAbsolutePath());

Probably in some case the solution with deletion of the file is not acceptable. For instance, if you add to the same zip file several entries. But in my use case it is OK.



回答2:

I tried using the normal ZipInputStream and related classes, but kept having issues, so the problem did not seem related to NIO. A colleague of mine found this question on SO: Extracting zipped file from ResourceStream throws error "Invalid stored block lengths"

So I tried adding this snippet to my pom.xml as well:

<properties>
    <project.build.sourceEncoding>ISO-8859-1</project.build.sourceEncoding>
</properties>

After this, all problems disappeared and all my tests turned green. I did not revert back to NIO as I was happy enough getting to a working solution, but I'm pretty sure this would solve the problem on NIO as well.

Posted here in hopes that it helps somebody having the same issue some day.



回答3:

Maybe you didn't used the ZipInputStream class ? What is on line 326 ?

Here is some example for decompressing and extracting zip files. http://www.oracle.com/technetwork/articles/java/compress-1565076.html

FileInputStream fis = new FileInputStream("figs.zip"); ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));

Once a ZIP input stream is opened, you can read the zip entries using the getNextEntry method which returns a ZipEntry object. If the end-of-file is reached, getNextEntry returns null: