Java ZipFileSystem在遍历时不保留物理顺序

时间:2018-08-22 07:27:15

标签: java zip unzip nio2

让我们考虑一个非常简单的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

虽然这看起来并不像是一个大问题,但它是一个巨大的问题,因为该META-INF/META-INF/MANIFEST.MF会根据JAR规范进入第一个条目,因此将被拒绝。 / p>

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

所有内容均使用Java 8、10和11-ea进行了测试。

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

1 个答案:

答案 0 :(得分:2)

ZipFileSystem是对基础zip文件的抽象,允许您将其与FileSystem的任何其他实现一样对待。 从根/开始,使其以您期望的常规树状结构运行非常有意义。如果您想轻松地从zip复制文件到zip,那么就好了,就像在常规目录之间进行复制一样。缺点是您无法控制zip本身。

ZipInputStream是较低级别的抽象,您可以控制结构和其他zip文件特定的内容。缺点是您可能必须编写更多代码。

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

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

因此ZipFileSystem为您提供了更高抽象度的好处,但具有诸如内存使用率,对zip文件详细信息的控制较少等缺点。 ZipXXXStream为您提供了有关zip的低级视图,处理了zip条目和其他内部细节,而这并不是您始终需要的。