【问题标题】:Java get the top level folder from zip fileJava从zip文件中获取顶级文件夹
【发布时间】:2015-05-31 22:40:28
【问题描述】:

我有点陷入这个问题。我只想打印 zip 文件中的顶级目录。例如,我有一个具有以下结构的 zip 文件:

Sample.zip
    - sound
          - game
                -start.wav
                -end.wav
          - Intro
    - custom
          - Scene
                - fight
          - Angle
       ..............

上图显示:Sample.zip有2个文件夹(sound和custom),sound里面有game和Intro等2个文件夹...

现在我知道如何打开并从 zip 文件中获取目录:例如(工作代码)

try {
    appFile = ("../../Sample.zip"); // just the path to zip file
    ZipFile zipFile = new ZipFile(appFile);
    Enumeration<? extends ZipEntry> entries = zipFile.entries();
    while (entries.hasMoreElements()) {
        ZipEntry entry = entries.nextElement();
        if(entry.isDirectory()){
            String dir = entry.getName();
            File file = new File(dir);
            System.out.println(file.getParent());
        }
    }
} catch (IOException e) {
    System.out.println("Error opening Zip" +e);
}

现在我也知道我可以使用.getParent()(如您在上面看到的)来获取顶级目录,但是上面的实现没有奏效。它会列出所有目录,比如

 null   
 sound
 game
 null
 custom
 scene
 Angle 

我的问题是我如何才能只打印顶级文件夹,在上述情况下,soundcustom

如有任何提示,我将不胜感激。

【问题讨论】:

  • @Ducan:我已经用什么不起作用(输出)更新了这个问题。
  • 首先打印所有条目的名称。然后只打印目录条目的名称。现在阅读输出并尝试找出如何区分顶级目录条目和非顶级目录条目。

标签: java file zip directory


【解决方案1】:

实际上我按照@JB Nizet 的建议做了以下工作并得到了解决(它确实有效):

try {
    appFile = ("../../Sample.zip"); // just the path to zip file
    ZipFile zipFile = new ZipFile(appFile);
    Enumeration<? extends ZipEntry> entries = zipFile.entries();
    while (entries.hasMoreElements()) {
        ZipEntry entry = entries.nextElement();
        if(entry.isDirectory()){
            File file = new File(entry.getName());
            if(file.getParent() == null){
               System.out.println(file.getName());
            }
        }
    }
} catch (IOException e) {
    System.out.println("Error opening Zip" +e);
}

上述解决方案有效,因为顶级目录没有父目录,因此返回 null 作为输出。所以我只是循环目录看看他们是否有父母,如果他们没有任何父母,那么他们就是顶级目录。

【讨论】:

  • 这是不正确的。它只是碰巧起作用,因为您在当前目录中没有名为 sound 或 game 的目录。您不需要使用文件。只需从名称中删除尾随的/,然后查看生成的名称是否仍包含/。如果不是,它是一个顶级目录。
  • @JBNizet :对不起,我没有明白你的逻辑。你能举个小例子吗?
  • boolean isTopLevelDirectory(ZipEntry e) { return e.isDirectory() &amp;&amp; !e.getName().substring(0, e.getName().length() - 1).contains("/"); }
  • @JBNizet :谢谢我现在知道了,它正在工作。您能否将其发布为答案,以便我可以接受并将此问题标记为已回答。
【解决方案2】:

你可以使用类似的东西:

    try{
        String appFile = "../file.zip"; // just the path to zip file
        ZipFile zipFile = new ZipFile(appFile);
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            if(entry.isDirectory() && !entry.getName().matches("\\S+/\\S+")){ //it's a top level folder
                System.out.println(entry.getName());
            }
        }
    } catch (IOException e) {
        System.out.println("Error opening Zip" +e);
    }

【讨论】:

  • 抱歉,您的解决方案将列出所有目录。
  • 这很奇怪,因为目录“sound/game/”(来自 entry.getName())在名称中包含 /,它应该被正则表达式条件排除
  • 是的,我认为您的回答应该有效。我已经解决了,但是我所做的只是一个解决方法。
【解决方案3】:

也许这段代码会帮助你使用 InputStream

            String topFolder="";
            String topFolder2="";
            Boolean hasTopFolder=true;
            try{
            File dir = new   File(path+"/html5"+catalogue.getIdProduit());
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String outputFolder= "path/to/outputFolder";       
            InputStream input = file.getInputstream();

            //get the zip file content
            ZipInputStream zis = new ZipInputStream(input);
            //get the zipped file list entry

            ZipEntry ze = zis.getNextEntry();

            while(ze!=null){

                if (ze.isDirectory()) {
                    System.out.println("is directory : "+ ze.getName());
                    if ("".equals(topFolder)){
                        topFolder = ze.getName().split("/")[0];                   
                        System.out.println("is directory topFolder : "+ ze.getName());

                    }

                    if (("".equals(topFolder2)) && (!topFolder.equals(ze.getName().split("/")[0]))){
                        hasTopFolder=false;
                        topFolder2=ze.getName().split("/")[0];
                        System.out.println("is directory topFolder2 : "+ ze.getName());
                    }
                    ze = zis.getNextEntry();              
                    continue;

                }

                String fileName = ze.getName();
                File newFile = new File(outputFolder + File.separator + fileName);

                System.out.println("file unzip : "+ newFile.getAbsoluteFile());

                 //create all non exists folders
                 //else you will hit FileNotFoundException for compressed folder
                 new File(newFile.getParent()).mkdirs();

                 FileOutputStream fos = new FileOutputStream(newFile);             

                 int len;
                 while ((len = zis.read(buffer)) > 0) {
                     fos.write(buffer, 0, len);
                 }

                 fos.close();   
                 ze = zis.getNextEntry();
                 }
                 zis.closeEntry();
                 zis.close();
                 System.out.println("Done");
            }
            catch(IOException e){
                e.printStackTrace();
            }



            if (hasTopFolder){
                topFolder="/"+topFolder;
            }
            else 
                topFolder="";

【讨论】:

    【解决方案4】:

    下面的方法呢:

    /**
     * Get the root folders within a zip file
     *
     * @param zipFile the zip file to be used. E.g. '/home/foo/bar.zip'
     * @return a list containing all root folders
     * @throws Exception if case the zip file cannot be found or read.
     */
    public static List<String> getGetRootDirectoriesWithinZip(String zipFile) throws Exception {
        Set<String> set = new LinkedHashSet();
        //get the zip file content stream
        ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFile));
    
        //get the zipped file set entry
        ZipEntry zipEntry = zipInputStream.getNextEntry();
        while (zipEntry != null) {
    
            String fileName = zipEntry.getName();
            Path path = Paths.get(fileName);
            int nameCount = path.getNameCount();
            for (int i = 0; i < nameCount; i++) {
                if (path != null && path.getParent() != null) {
                    path = path.getParent();
                }
    
            }
            set.add(path.toString());
            zipEntry = zipInputStream.getNextEntry();
        }
    
        List<String> retList = new ArrayList<>();
        retList.addAll(set);
        return retList;
    }
    

    【讨论】:

      【解决方案5】:

      这是对我有用的方法。

      我应该注意我使用StringUtils (Apache Lang3) 来计算多少次 “\”出现在 ZipEntry 路径中,但如果您不想使用 StringUtils,您可以制作 您自己的计数方法。

      public static ArrayList<ZipEntry> getZipContent(File file, int index) {
          try {
              ArrayList<String> innerFoldersPaths = new ArrayList<String>();
              ArrayList<ZipEntry> retEntries = new ArrayList<ZipEntry>();
              ZipFile zipFile = new ZipFile(file);
              Enumeration<? extends ZipEntry> entries = zipFile.entries();
              while (entries.hasMoreElements()) {
                  ZipEntry entry = entries.nextElement();
                  // If you also want to get files remove the "if (entry.isDirectory())" statement.
                  if (entry.isDirectory()) {
                      String backSlashName = entry.getName().replace("/", "\\"); // Important to do this.
                      if (StringUtils.countMatches(backSlashName, "\\") > index - 1) { // Using Apache StringUtils
                          String folder[] = backSlashName.split(Pattern.quote("\\"));
                          String finalFolder = "";
                          // Getting the folders path inside the .zip file .
                          for (int i = 0; i < index; i++) {
                              folder[i] = folder[i] + "\\";
                              finalFolder = finalFolder + folder[i];
                          }
                          finalFolder = finalFolder.replace("\\", "/"); // Important to do this.
                          if (innerFoldersPaths.contains(finalFolder)) {
                          } else {
                              innerFoldersPaths.add(finalFolder);
                          }
                      }
                  }
              }
              for (String backSlashName : innerFoldersPaths) {
                  retEntries.add(zipFile.getEntry(backSlashName));
              }
              zipFile.close();
              return retEntries;
          } catch (Exception exception) {
              // handle the exception in the way you want.
              exception.printStackTrace();
          }
          return null;
      }
      

      这个方法的用法:

          File file = new File("Your zip file here");
          for (ZipEntry zipEntry : getZipContent(file, 1)) { // This would return all the folders in the first file
              // Do what ever your wantt with the ZipEntry
              System.out.println(zipEntry.getName());
          }
      

      如果您想获取第一个文件夹之后的所有文件夹, 您可以通过将索引更改为您想要获取的文件夹的深度来做到这一点。

      【讨论】:

        【解决方案6】:

        在 Kotlin 中使用这个乐趣

        fun getRootFolderName(fileAddress: String): String {
            if (File(fileAddress).parent == null || ("" + File(fileAddress).parent).length < 1) return File(fileAddress).name
            return getRootFolderName("" + File(fileAddress).parent)
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-06
          • 1970-01-01
          • 1970-01-01
          • 2018-07-11
          • 1970-01-01
          相关资源
          最近更新 更多