Nepal12
Nepal12

Reputation: 593

Java get the top level folder from zip file

I kind of stuck in this problem. I want to print only the top level directory from a zip file. For example I have a zip file with following structure:

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

Above figure shows: the Sample.zip has 2 folders (sound and custom), and inside sound there are 2 folders game and Intro and so on...

Now I know how to open and grab the directory from zip file: For example (working code)

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);
}

Now I also know I can use .getParent()(as you see above) to get the top level dir, but the above implementation has not worked. It'll list out all the directory , like

 null   
 sound
 game
 null
 custom
 scene
 Angle 

My question is how can I actually print only the top level folders, In above scenario , sound and custom ?

For any sort of hint, I'll be thankful.

Upvotes: 3

Views: 7873

Answers (5)

hms11
hms11

Reputation: 54

This is the method that worked for me.

I should note that I am using StringUtils (Apache Lang3) to count how many times "\" appears in the ZipEntry path, although if you don't want to use StringUtils you could make your own method for counting.

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;
}

The usage of this method:

    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());
    }

If you want to get all the folders past the first one, you could do it by changing the index to how deep the folders that you want to get are.

Upvotes: 0

lidox
lidox

Reputation: 1971

What about following method:

/**
 * 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;
}

Upvotes: 1

Spartan
Spartan

Reputation: 1174

Maybe this code will help you with using 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="";

Upvotes: 1

Nepal12
Nepal12

Reputation: 593

Actually I did following as suggested by @JB Nizet and get a work around(it actually work ):

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);
}

The above solution has worked because the top level dir has no parent and therefore returned null as output. So I just loop around the directories to see if they have parents, if they dont have any parent then they are top level directory.

Upvotes: 3

Le Funes
Le Funes

Reputation: 51

You can use something like that:

    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);
    }

Upvotes: 2

Related Questions