Home > Software engineering >  ZipOutputStream does not create new entries for Directories
ZipOutputStream does not create new entries for Directories

Time:04-19

I am trying to create directories in a .zip file but only one directory is being created in the .zip. I'm not sure why only the first directory gets created. zip() method gets called everytime theres a directory.

Method to list files:

private Set<String> listFiles(String path){

        File f = new File(path);
        Set<String> files = new HashSet<>();

        for(File file : Objects.requireNonNull(f.listFiles())){
            files.add(file.getPath());
        }
        return files;
    }

Method to zip:

 private void zip(Set<String> path){
        try {
            BufferedInputStream bufferedInputStream = null;
            BufferedOutputStream bufferedOutputStream;
            ZipOutputStream zipOutputStream;

            File f;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

                bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("/sdcard/Android/data/com.kpwnapps.pmmpplugins/files/PocketMine-MP/test.zip"));
                zipOutputStream= new ZipOutputStream(bufferedOutputStream, StandardCharsets.UTF_8);

                for (String file : path){

                    f = new File(file);

                    if (f.isDirectory()){
                        zipOutputStream.putNextEntry(new ZipEntry(f.getName()   "/"));
                        zip(listFiles(f.getPath()));
                    }else {
                      
                        bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
                        zipOutputStream.putNextEntry(new ZipEntry(f.getName()));
                        IOUtils.copy(bufferedInputStream, zipOutputStream);
                        zipOutputStream.closeEntry();
                    }
                     */

                }

                if (bufferedInputStream != null){
                    bufferedInputStream.close();
                }

                zipOutputStream.flush();
                zipOutputStream.close();

            }
        }catch (Exception ignored){
        }

    }

CodePudding user response:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; 

public class ZipFolders
{
    public static void main(String[] args) throws IOException
    {    
        List<String> listOfDir = new ArrayList<String>();

        String dirpath1 = "/home/administrator/Documents/ZipTest/folder1";
        String dirpath2 = "/home/administrator/Documents/ZipTest/folder2";

        String ZipName = "/home/administrator/Documents/ZipTest/output.zip";
        listOfDir.add(dirpath1);
        listOfDir.add(dirpath2);

        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(ZipName));
        zipDirectories(listOfDir,zos); 
        zos.close(); 
        System.out.println("Zip Created Successfully");
    }

    private static void zipDirectories(List<String> listOfDir, ZipOutputStream zos) {
        for(String dirPath:listOfDir){
            try {
                zipdirectory(dirPath, zos);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public static void zipdirectory(String dirpath, ZipOutputStream zos) throws IOException
    {
        File f = new File(dirpath);
        String[] flist = f.list();
        for(int i=0; i<flist.length; i  )
        {
            File ff = new File(f,flist[i]);
            if(ff.isDirectory())
            {
                zipdirectory(ff.getPath(),zos);    
                continue;
            }
            String fileName = ff.getPath().substring(ff.getPath().lastIndexOf('/'));

            String folder = dirpath.substring(dirpath.lastIndexOf('/') 1);

            ZipEntry entries = new ZipEntry(folder fileName);
            zos.putNextEntry(entries);
            FileInputStream fis = new FileInputStream(ff);
            int buffersize = 1024;
            byte[] buffer = new byte[buffersize];
            int count;
            while((count = fis.read(buffer)) != -1)
            {
                zos.write(buffer,0,count);    
            }
            fis.close();
        }
    }
}

CodePudding user response:

I'm mildly surprised that this even works.

When your zip() method calls itself recursively it creates a new FileOutputStream with the same filename as the previous call. That means that your recursive calls write on top of each other instead of appending to a single zip file.

You should open the FileOutputStream / ZipOutputStream only once and then use it for zipping all files and directories.

That means rewriting some of your code so that at the first level of zipping you create the zipOutputStream and then call an internal method zip(path, zipOutputStream). The recursive calls also must call this zip(path, zipOutputStream) method.

This will look something like

private void zip(Set<String> path) {
    // create FileOutputStream, ZipOutputStream
    ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
    // call worker method
    zip(path, zipOutputStream);
    // close output stream
    zipOutputStream.flush();
    zipOutputStream.close();
}

private void zip(Set<String> path, ZipOutputStream zipOutputStream) {
    // loop over paths
        if (f.isDirectory()) {
            zipOutputStream.putNextEntry(new ZipEntry(f.getName()   "/"));
            zip(listFiles(f.getPath()), zipOutputStream);
        }
    // end of loop over paths
}
  • Related