java ZipInputStream.getNextEntry()是如何工作的?

t98cgbkg  于 2023-05-05  发布在  Java
关注(0)|答案(5)|浏览(298)

假设我们有这样的代码:

File file = new File("zip1.zip");
ZipInputStream zis = new ZipInputStream(new FileInputStream(file));

假设您有一个.zip文件,其中包含以下内容:

  • zip1.zip
  • hello.c
  • world.java
  • 文件夹1
  • foo.c
  • bar.java
  • foobar.c

zis.getNextEntry()将如何遍历它?
它会返回hello.c、world.java、folder 1、foobar.c并完全忽略folder 1中的文件吗?
或者返回hello.c、world.java、folder 1、foo.c、bar.java,然后返回foobar.c?
它甚至会返回folder 1,因为它在技术上是一个文件夹,而不是一个文件?
谢谢!

mbjcgjjk

mbjcgjjk1#

嗯……让我们看看:

ZipInputStream zis = new ZipInputStream(new FileInputStream("C:\\New Folder.zip"));
        try
        {
            ZipEntry temp = null;
            while ( (temp = zis.getNextEntry()) != null ) 
            {
             System.out.println( temp.getName());
            }
        }

输出:
新建文件夹/
新建文件夹/folder 1/
新文件夹/folder 1/bar.java
新建文件夹/folder 1/foo. c
新建文件夹/foobar. c
新建文件夹/hello. c
新文件夹/world.java

3qpi33ja

3qpi33ja2#

是的。它也会打印文件夹名称,因为它也是zip中的一个条目。它也将打印在相同的顺序,因为它是显示在zip。您可以使用下面的测试来验证您的输出。

public class TestZipOrder {
    @Test
    public void testZipOrder() throws Exception {
        File file = new File("/Project/test.zip");
        ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
        ZipEntry entry = null;
        while ( (entry = zis.getNextEntry()) != null ) {
         System.out.println( entry.getName());
        }
    }
}
eimct9ow

eimct9ow3#

摘录自:https://blogs.oracle.com/CoreJavaTechTips/entry/creating_zip_and_jar_files
java.util.zip 库为ZipOutputStream的添加条目提供了某种级别的控制。
首先,向ZipOutputStream添加条目的顺序是它们在.zip文件中物理位置的顺序

您可以操作ZipFile的entries()方法返回的条目枚举,以按字母顺序或大小顺序生成列表,但条目仍按写入输出流的顺序存储。

所以我相信你必须使用entries()方法来查看它的迭代顺序。

ZipFile zf = new ZipFile("your file path with file name");
    for (Enumeration<? extends ZipEntry> e = zf.entries();
    e.hasMoreElements();) {
      System.out.println(e.nextElement().getName());
    }
gcxthw6b

gcxthw6b4#

zip文件内部目录是zip中所有文件和目录的“平面”列表。getNextEntry将遍历该列表,并按顺序标识zip文件中的每个文件和目录。
zip文件格式有一个变体,它没有中心目录,在这种情况下(如果它被处理的话),我怀疑你会遍历zip中的所有实际文件,跳过目录(但不跳过目录中的文件)。

2exbekwf

2exbekwf5#

我想更详细地解释为什么Vikram's answer是正确的,而acceptedhighest scoring的答案可能会误导或不完整。
正如Vikram所说(正确)
将条目添加到ZipOutputStream的顺序是它们在.zip文件中物理位置的顺序。
我发现这部分公认的答案可能会产生误导:
它也将打印在相同的顺序,因为它是显示在zip。
我想指出的一个问题是,文件夹中的文件不保证会连续返回。
不同的工具以不同的顺序显示zip文件内容。特别是,任何带有GUI的工具都会将文件夹中的所有文件显示在一起,而zip中的实际文件可能会分散在各处。
让我们看看下面的两个场景。

场景一:按树顺序排列的文件

从这样的文件树开始

$ tree
├── folder1
│   ├── bar.java
│   └── foo.c
├── foobar.c
├── hello.c
└── world.java

现在让我们使用Linuxzip命令从该目录创建一个zip。

$ zip -r zip1.zip ./*
  adding: folder1/ (stored 0%)
  adding: folder1/foo.c (stored 0%)
  adding: folder1/bar.java (stored 0%)
  adding: foobar.c (stored 0%)
  adding: hello.c (stored 0%)
  adding: world.java (stored 0%)

请注意这些文件的添加顺序。这与使用ZipOutputStream时迭代的顺序相同。用下面的脚本测试一下(借用Zoop的答案)

jshell> import java.util.zip.*;
   ...> ZipInputStream zis = new ZipInputStream(new FileInputStream("./zip1.zip"));
   ...> ZipEntry temp = null;
   ...> while ( (temp = zis.getNextEntry()) != null )
   ...> {
   ...>     System.out.println(temp.getName());
   ...> }
folder1/
folder1/foo.c
folder1/bar.java
foobar.c
hello.c
world.java

场景二:文件散落

如果我们以不同的顺序添加文件,那么它们将以不同的顺序迭代。让我们尝试使用zip命令创建一个新文件,并将文件逐个添加到文件夹中:

zip -m zip1.zip ./hello.c
zip -m zip1.zip ./folder1
zip -m zip2.zip ./folder1/foo.c
zip -m zip1.zip ./world.java
zip -m zip1.zip ./foobar.c
zip -m zip1.zip ./folder1/bar.java # Notice we're adding this LAST

现在,如果我们遍历这些文件,您将看到folder1/bar.java是最后一个条目,因为它是最后添加的。它不会与其他文件夹内容一起返回。目录条目不会重复或紧接在它之前。

hello.c
folder1/
folder1/foo.c
world.java
foobar.c
folder1/bar.java

zip规范非常复杂,所以在使用ZipInputStream时要非常小心。

相关问题