Java Zip文件系统在遍历时不保留物理顺序



让我们考虑一个非常简单的Java片段:

String pathUriStr = Paths.get(args[0]).toUri().toASCIIString();
URI zipUri = URI.create("jar:" + pathUriStr);
FileSystem zip = null;
try {
zip = FileSystems.newFileSystem(zipUri, Collections.emptyMap());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Path zipRoot = zip.getPath("/");
System.out.println("ZipFileSystem:");
FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
System.out.println(file);
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
System.out.println(dir);
return super.preVisitDirectory(dir, attrs);
}
};
try {
Files.walkFileTree(zipRoot, visitor);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

输出为:

ZipFileSystem:
/
/images
/images/ant_logo_large.gif
/org
/org/apache
...
/META-INF
/META-INF/LICENSE.txt
/META-INF/MANIFEST.MF

对'ZipInputStream'做同样的事情:

System.out.println("ZipInputStream:");
try (InputStream is = Files.newInputStream(Paths.get(args[0]), StandardOpenOption.READ);
ZipInputStream zipIs = new ZipInputStream(is)) {
ZipEntry entry = null;
while((entry = zipIs.getNextEntry()) != null) {
System.out.println(entry);
zipIs.closeEntry();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

给我:

ZipInputStream:
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
...
META-INF/LICENSE.txt
images/
images/ant_logo_large.gif

输出与unzip(1)相同:

$ unzip -l ~/ant-1.5.jar
Archive:  /net/home/osipovmi/ant-1.5.jar
Length      Date    Time    Name
---------  ---------- -----   ----
0  07-09-2002 11:13   META-INF/
460  07-09-2002 11:13   META-INF/MANIFEST.MF
0  07-09-2002 11:12   org/
0  07-09-2002 11:12   org/apache/
.......................................................
2766  07-09-2002 11:10   META-INF/LICENSE.txt
0  04-30-2002 10:10   images/
5360  03-18-2002 14:57   images/ant_logo_large.gif
---------                     -------
1329851                     435 files

虽然这看起来首先不像是一个问题,但这是一个巨大的问题,因为这个 JAR 会被拒绝,因为根据 JAR 规范META-INF/META-INF/MANIFEST.MF不是第一个条目。

我的用例非常相似,我想使用 ZIP 文件,并希望要求一些条目成为第一个快速验证输入的条目,而不必寻找文件的末尾。

全部使用 Java 8、10 和 11-ea进行了测试。

那么问题来了,为什么 Zip 文件系统不保留流中出现的顺序?

ZipFileSystem

是底层zip文件的抽象,允许您以与文件系统的任何其他实现相同的方式处理它。 让它在你期望的常规树状结构中工作是完全有意义的,从根/开始。如果您想轻松地从 zip 复制文件/将文件复制到 zip,就像在常规目录之间一样,这非常有用。这样做的缺点是你失去了对zip本身的一些控制。

ZipInputStream是一个低级抽象,您可以在其中控制结构和其他特定于 zip 文件的内容。缺点是您可能需要编写更多代码。

示例:您要将文件从一个 zip 复制或移动到另一个 zip:

使用ZipFileSystem这相当于将文件从一个目录移动到另一个目录,并且该代码适用于FileSystem的任何实现。使用 zip 流,您必须手动处理源 zip 文件,找到正确的条目,删除条目,然后将其添加到第二个 zip 文件中,在此过程中重写文件。这是 1 行代码与几行、循环和其他样板。

因此,ZipFileSystem为您提供了更高抽象的好处,但也有缺点,例如内存使用,对zip文件细节的控制较少等。ZipXXXStream为您提供了zip的低级视图,处理zip条目和其他内部细节,这不是您总是需要的。

最新更新