Android: Get Number of Files within Zip?

Viewed 7318

I have a question that seems easy but I cannot seem to get it to work properly.

I have a zip file within my 'assets' folder that I need to unzip and I have a ProgessBar in which I want to display to the user how the progress is going.

I have everything working but I want to set the ProgessBar max value to be the number of files within the zip file. The number of files within this folder will sometimes change so I want the ProgessBar to be relative to how many files are contained within the zip.

I'm using the ZipInputStream-API but does not seem there is a way to get the number of files within the zip file. The only way I can of think of is doing this:

   ZipInputStream zin = new ZipInputStream(getAssets().open(
                                "myFile.zip"));
   int numFiles = 0;
   int increment = 0;
   while (zin.getNextEntry() != null) {
     numFiles++;
    }

    ZipEntry ze = null;
    //Set the Max..value here..
    progessBar.setMax(numFiles);                
    while ((ze = zin.getNextEntry()) != null) {
       increment++;
       progessBar.setProgress(increment);
    }

This works but having two while loops seems a bit redundant which are basically doing the same thing.

I know that there is a ZipFile-API which has a size()-method, but it requires a path to the file and since my file is located within the 'assets' folder I am pretty sure the only way to read from this directory is by streaming.

Is there a way for me to accomplish this?

4 Answers

this is my solution based on @davorb idea which is to show progress based on file size and not content of zip file.

import android.content.Context;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipUtility {
    private final String TAG = "Decompress";
    private ZipExtractionCallback zipExtractionCallback;

    public ZipUtility(ZipExtractionCallback zipExtractionCallback) {
        this.zipExtractionCallback = zipExtractionCallback;
    }
//
//    private void unzipFromAssets(Context context, String zipFile, String destination) {
//        try {
//            if (destination == null || destination.length() == 0)
//                destination = context.getFilesDir().getAbsolutePath();
//            new File(destination).delete();
//            InputStream stream = context.getAssets().open(zipFile);
//            unzip(stream, destination);
////            SharedPreferenceHelper.Write(context,
////                    SharedPreferenceConst.SharedPreferenceName,
////                    SharedPreferenceConst.MapExtracted,
////                    "1");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

    private boolean deleteDirectory(String file) /*throws IOException, InterruptedException */ {

        try {
            if (new File(file).exists()) {
                String deleteCommand = "rm -rf " + file/*.getAbsolutePath()*/;
                Runtime runtime = Runtime.getRuntime();
                Process process = runtime.exec(deleteCommand);
                process.waitFor();
                return true;
            }
        } catch (Exception ignore) {
        }

        return false;
    }

    public void unzipFromPath(Context context, String zipFilePath, String destination) {

        try {
            if (destination == null || destination.length() == 0)
                destination = context.getFilesDir().getAbsolutePath();
            zipExtractionCallback.progress(0, "حذف فایل های قدیمی...");
            deleteDirectory(destination + "html");
            unzip(zipFilePath, destination);
            zipExtractionCallback.progress(0, "حذف فایل اضافی...");
            deleteDirectory(zipFilePath);
        } catch (IOException e) {
            zipExtractionCallback.error("خطا هنگام عملیات استخراج : " + e.getMessage());
            e.printStackTrace();
        }
        zipExtractionCallback.finish();
    }
//
//    public static void unzip(String zipFile, String location) {
//        try {
//            FileInputStream fin = new FileInputStream(zipFile);
//            unzip(fin, location);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
//
//    }

    private void unzip(String zipFilePath, String destination) throws IOException {
        long size = new File(zipFilePath).length();
        long decompressedSize = 0;
        InputStream stream = new FileInputStream(new File(zipFilePath));
        dirChecker(destination, "");
//        int entries = 0;
        int total = 0;
        ZipInputStream zin = new ZipInputStream(stream);

//        while ((zin.getNextEntry()) != null) {
//            if (entries % 100 == 0)
//                zipExtractionCallback.progress(0, "در حال خواندن محتویات:" + entries + " فایل");
//            entries++;
//        }
        zin.close();
        stream = new FileInputStream(new File(zipFilePath));
        int p = 0;
        long totalBytes = 0;
        int BUFFER_SIZE = 1024 * 10;
        byte[] buffer = new byte[BUFFER_SIZE];
        try {
            zin = new ZipInputStream(stream);
            ZipEntry ze = null;
            while ((ze = zin.getNextEntry()) != null) {
                decompressedSize += ze.getSize();
                //Log.v(TAG, "Unzipping " + ze.getName());
                if (ze.isDirectory()) {
                    dirChecker(destination, ze.getName());
                } else {
                    File f = new File(destination, ze.getName());
                    if (!f.exists()) {
                        boolean success = f.createNewFile();
                        if (!success) {
                            //Log.w(TAG, "Failed to create file " + f.getName());
                            continue;
                        }
                        FileOutputStream fout = new FileOutputStream(f);
                        //BufferedOutputStream out = new BufferedOutputStream(fout);
                        int count;
                        while ((count = zin.read(buffer)) != -1) {
                            fout.write(buffer, 0, count);
                            //out.write(buffer, 0, count);
                            totalBytes += count;
                        }
                        zin.closeEntry();
                        fout.close();
                    }
                }
//                int progress = 1 + (total++ * 100 / entries);
                if (size < decompressedSize)
                    size = decompressedSize;
                int progress = (int) ( (totalBytes * 100L / size));
                if (p < progress)
                    zipExtractionCallback.progress(progress, "در حال استخراج از حالت فشرده:");
                p = progress;
            }
            zin.close();
        } catch (Exception e) {
            zipExtractionCallback.error("خطا هنگام عملیات استخراج : " + e.getMessage());
            Log.e(TAG, "unzip", e);
        }
    }

    private void dirChecker(String destination, String dir) {
        File f = new File(destination, dir);

        if (!f.isDirectory()) {
            boolean success = f.mkdirs();
            if (!success) {
                Log.w(TAG, "Failed to create folder " + f.getName());
            }
        }
    }


    public interface ZipExtractionCallback {

        void progress(int progress, String status);

        void finish();

        void error(String error);
    }

}

Example of using it :

private void ExtractMap(String zipFilePath,Context context) {

    new Thread(new Runnable() {
        @Override
        public void run() {

            ZipUtility zipUtility = new ZipUtility(new ZipUtility.ZipExtractionCallback() {
                @Override
                public void progress(int progress, String status) {
                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                             //todo handle ui
                        }
                    });
                }

                @Override
                public void finish() {

                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //todo handle ui
                        }
                    });

                }

                @Override
                public void error(String error) {
                    ((UpdateActivity) context).runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                           //todo handle ui
                        }
                    });
                }
            });

            zipUtility.unzipFromPath(context,
                    zipFilePath,
                    context.getFilesDir().getAbsolutePath() + File.separator);


        }
    }).start();
}
Related