Question

I have several zip files that each contains several files too which I want to extract using the ZipInputStream class. Among them are some images. When I try to extract these images using the BufferedOutputStream they are decompressed partially and the images are incomplete.

private void extractArchives() {

    ZipInputStream zis;

    File archiveDir = new File(
             Environment.getExternalStorageDirectory().getAbsolutePath() +
     "/archives/");

    File[] files = archiveDir.listFiles();

    for (int i = 0; i < files.length; ++i)
    {
        File file = files[i];

        try
        {
            zis = new ZipInputStream(new FileInputStream(file));
            ZipEntry ze;

            while ((ze = zis.getNextEntry()) != null)
            {
                BufferedOutputStream bos;
                byte[] buffer = new byte[102400];
                int count;

                while ((count = zis.read(buffer)) != -1)
                {
                    String fileName = ze.getName();

                    if (fileName.endsWith(".jpg"))
                    {
                        path += File.separator + fileName;
                        bos = new BufferedOutputStream(new FileOutputStream(path));
                        bos.write(buffer, 0, count);
                        bos.close();
                    }
                }
            }

            zis.close();

        }

        catch(FileNotFoundException e) { continue; }

        //If the file is not a zip file or is a directory
        catch (IOException e) { continue; }

    }
}

Is there anything wrong with the code above? Does using BufferedOutputStream cause this problem? I appreciate any ideas. Thanks.

Was it helpful?

Solution 2

Focusing on the loop that iterates over the zip entries, the problem is that you were reading at most 102400 bytes from a zip entry and then writing that to a new file. The next maximum 102400 bytes if the same image file was written to a new file. If the path name was the same as the old file, it would overwrite the old file. But since you were constantly appending to the local variable 'path', I'm not sure where the data ended up.

Pull the opening of the FileOutputStream out of the inner loop, and keep writing to the same OutputStream until you can read no more bytes from the current ZipEntry. Only then move on to the next ZipEntry and to the next OutputStream.

This is a standard pattern to read and copy between streams in Java so I can fix your code without having the definitions of the files, path and zis but it would help if you can post an actual compiling code example so that other people can benefit from this too.

Another improvement you need in production code, is to wrap bos.close() in a try/finally block so that the output file is also closed if there was an exception while reading from the input.

        while ((ze = zis.getNextEntry()) != null) {
            String fileName = ze.getName();

            if (fileName.endsWith(".jpg")) {
                String filepath = path + File.separator + fileName;
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filepath));
                byte[] buffer = new byte[102400];
                int count;
                while ((count = zis.read(buffer)) != -1) {
                    bos.write(buffer, 0, count);
                }
                bos.close();
            }
        }

OTHER TIPS

I modified the method according to what Erwin said and now it works:

private void extractArchives() {

    File archiveDir = new File(
                Environment.getExternalStorageDirectory().getAbsolutePath() +
                "/archives/");

    String archivePath = archiveDir.getAbsolutePath();

    File[] files = archiveDir.listFiles();

    for (int i = 0; i < files.length; ++i)
    {
        File file = files[i];

        if(!file.isDirectory())
        {
            try {

                ZipInputStream zis = new ZipInputStream(new FileInputStream(file));
                ZipEntry entry = zis.getNextEntry();

                while (entry != null)
                {
                    if(entry.getName().endsWith(".jpg"))
                    {
                        String imagePath = themePath + File.separator + entry.getName();

                        BufferedOutputStream bos = new BufferedOutputStream(
                                    new FileOutputStream(imagePath));

                        byte[] buffer = new byte[4096];

                        int read = 0;

                        while ((read = zis.read(buffer)) != -1) bos.write(buffer, 0, read);

                        imagePath = "";

                        bos.close();
                    }

                    zis.closeEntry();

                    entry = zis.getNextEntry();
                }

                zis.close();
            }

            catch (FileNotFoundException e) {}

            catch (IOException e) {}
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top