Download and Extract Zip File in Android [duplicate]
Asked Answered
B

4

26

My application is downloading zip file from the server and extract this zip file and save files into sd card but problem is if i am downloading 4-5 MB zip files and extract it, this is working good but if i am downloading 30-35 MB zip file this will give me error, sorry for my bad English communication.

The Below is my Code for Download & Unzip Zip File:-

public class UnzipManager {
    private static String BASE_FOLDER;

    public static Context localContext;
    public static String passurl;
    public static int count;
    public static Context context;
    /*
     * You can use this flag to check whether Unzippingthread is still running..
     */
    public static boolean isDownloadInProgress;
    /*
     * After unzipping using this flag ,you can check whether any low memory
     * exceptions Occurred or not..and alert user accordingly..
     */
    public static boolean isLowOnMemory;
    public static int i = 0;

    public static ZipEntry zipEntry;

    public static void startUnzipping(Context ctx, int c, String url) {
        context = ctx;
        count = c;
        /*
         * MAKE SURE THAT localContext VARIABLE HAS BEEN INITIALIZED BEFORE
         * INVOKING THIS METHOD.
         * 
         * ALSO MAKE SURE YOU HAVE SET "INTERNET" AND "NETWORK ACCESS STATE"
         * PERMISSIONS IN APPLICATION'S MANIFEST FILE.
         */
        Log.d("DEBUG", "In startUnzipping()");
        UnzipManager.BASE_FOLDER = Environment.getExternalStorageDirectory()
                + File.separator + "samples";
        /*
         *
         */

        Log.d("DEBUG", "BASE_FOLDER:" + UnzipManager.BASE_FOLDER);
        UnzipManager.isLowOnMemory = false;
        // Start unzipping in a thread..which is safer
        // way to do high cost processes..
        passurl = url;
        new UnzipThread().start();
    }

    private static class UnzipThread extends Thread {
        @Override
        public void run() {
            UnzipManager.isDownloadInProgress = true;
            Log.d("DEBUG", "Unzipping----------------------------");
            URLConnection urlConnection;
            try {
                /************************************************
                 * 
                 * IF you are unzipping a zipped file save under some URL in
                 * remote server
                 * **********************************************/
                URL finalUrl = new URL(passurl
                /* Url string where the zipped file is stored... */);
                urlConnection = finalUrl.openConnection();

                // Get the size of the ( zipped file's) inputstream from
                // server..
                int contentLength = urlConnection.getContentLength();
                Log.d("DEBUG", "urlConnection.getContentLength():"
                        + contentLength);
                /*****************************************************
                 * 
                 * YOU CAN GET INPUT STREAM OF A ZIPPED FILE FROM ASSETS FOLDER
                 * AS WELL..,IN THAT CASE JUST PASS THAT INPUTSTEAM OVER
                 * HERE...MAKE SURE YOU HAVE SET STREAM CONTENT LENGTH OF THE
                 * SAME..
                 * 
                 ******************************************************/
                ZipInputStream zipInputStream = new ZipInputStream(
                        urlConnection.getInputStream());
                /*
                 * Iterate over all the files and folders
                 */
                for (zipEntry = zipInputStream.getNextEntry(); zipEntry != null; zipEntry = zipInputStream
                        .getNextEntry()) {
                    Log.d("DEBUG", "Extracting: " + zipEntry.getName() + "...");

                    /*
                     * Extracted file will be saved with same file name that in
                     * zipped folder.
                     */


                    String innerFileName = BASE_FOLDER + File.separator
                            + zipEntry.getName();
                    File innerFile = new File(innerFileName);

                    /*
                     * Checking for pre-existence of the file and taking
                     * necessary actions
                     */
                    if (innerFile.exists()) {
                        Log.d("DEBUG",
                                "The Entry already exits!, so deleting..");
                        innerFile.delete();
                    }

                    /*
                     * Checking for extracted entry for folder type..and taking
                     * necessary actions
                     */
                    if (zipEntry.isDirectory()) {
                        Log.d("DEBUG", "The Entry is a directory..");
                        innerFile.mkdirs();
                    } else {
                        Log.d("DEBUG", "The Entry is a file..");
                        FileOutputStream outputStream = new FileOutputStream(
                                innerFileName);
                        final int BUFFER_SIZE = 2048;

                        /*
                         * Get the buffered output stream..
                         */
                        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
                                outputStream, BUFFER_SIZE);
                        /*
                         * Write into the file's buffered output stream ,..
                         */
                        int count = 0;
                        byte[] buffer = new byte[BUFFER_SIZE];
                        while ((count = zipInputStream.read(buffer, 0,
                                BUFFER_SIZE)) != -1) {
                            bufferedOutputStream.write(buffer, 0, count);
                        }
                        /***********************************************
                         * IF YOU WANT TO TRACK NO OF FILES DOWNLOADED, HAVE A
                         * STATIC COUNTER VARIABLE, INITIALIZE IT IN
                         * startUnzipping() before calling startUnZipping(), AND
                         * INCREMENT THE COUNTER VARIABLE OVER HERE..LATER YOU
                         * CAN USE VALUE OF COUNTER VARIABLE TO CROSS VERIFY
                         * WHETHER ALL ZIPPED FILES PROPERLY UNZIPPED AND SAVED
                         * OR NOT.
                         * 
                         * ************************************************
                         */
                        /*
                         * Handle closing of output streams..
                         */
                        bufferedOutputStream.flush();
                        bufferedOutputStream.close();
                    }
                    /*
                     * Finish the current zipEntry
                     */
                    zipInputStream.closeEntry();
                }
                /*
                 * Handle closing of input stream...
                 */
                zipInputStream.close();
                Log.d("DEBUG", "--------------------------------");
                Log.d("DEBUG", "Unzipping completed..");
                i = 1;

            } catch (IOException e) {
                Log.d("DEBUG", "Exception occured: " + e.getMessage());
                if (e.getMessage().equalsIgnoreCase("No space left on device")) {
                    UnzipManager.isLowOnMemory = true;
                }
                e.printStackTrace();
            }

            MainActivity.pd.dismiss();

            ((MainActivity)context).finish();       

            UnzipManager.isDownloadInProgress = false;
        }
    };
}

Logcat Error is:-

02-17 12:21:16.835: D/DEBUG(20562): Exception occured: /mnt/sdcard/samples/iPhone_zendura_Q4a/0.png (No such file or directory)
02-17 12:21:16.835: W/System.err(20562): java.io.FileNotFoundException: /mnt/sdcard/samples/iPhone_zendura_Q4a/0.png (No such file or directory)
02-17 12:21:16.906: W/System.err(20562):    at org.apache.harmony.luni.platform.OSFileSystem.open(Native Method)
02-17 12:21:16.906: W/System.err(20562):    at dalvik.system.BlockGuard$WrappedFileSystem.open(BlockGuard.java:232)
02-17 12:21:16.906: W/System.err(20562):    at java.io.FileOutputStream.<init>(FileOutputStream.java:94)
02-17 12:21:16.906: W/System.err(20562):    at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
02-17 12:21:16.906: W/System.err(20562):    at java.io.FileOutputStream.<init>(FileOutputStream.java:144)
02-17 12:21:16.906: W/System.err(20562):    at com.android.screens.UnzipManager$UnzipThread.run(UnzipManager.java:129)
Bowyer answered 17/2, 2012 at 6:53 Comment(1)
This is really a great way to download and Extract the zips.Balling
C
13

I wrote an IntentService that dose both the things together with progress :

Add following Service class to your Application (also declare it in your app's Manifest file) :

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ResultReceiver;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Created by Vaibhav.Jani on 6/4/15.
 */
public class FileDownloadService extends IntentService {

    private static int STATUS_OK = 100;

    private static int STATUS_FAILED = 200;

    private static final String DOWNLOADER_RECEIVER = "downloader_receiver";

    private static final String DOWNLOAD_DETAILS = "download_details";

    private static final String DOWNLOAD_STARTED = "download_started";

    private static final String DOWNLOAD_FAILED = "download_failed";

    private static final String DOWNLOAD_COMPLETED = "download_completed";

    private static final String DOWNLOAD_PROGRESS = "download_progress";

    public FileDownloadService() {

        super("");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Bundle bundle = intent.getExtras();

        if (bundle == null
                || !bundle.containsKey(DOWNLOADER_RECEIVER)
                || !bundle.containsKey(DOWNLOAD_DETAILS)) {

            return;
        }

        ResultReceiver resultReceiver = bundle.getParcelable(DOWNLOADER_RECEIVER);

        DownloadRequest downloadDetails = bundle.getParcelable(DOWNLOAD_DETAILS);

        try {

            assert downloadDetails != null;
            URL url = new URL(downloadDetails.getServerFilePath());

            URLConnection urlConnection = url.openConnection();

            urlConnection.connect();

            int lengthOfFile = urlConnection.getContentLength();

            Log.d("FileDownloaderService", "Length of file: " + lengthOfFile);
            downloadStarted(resultReceiver);

            InputStream input = new BufferedInputStream(url.openStream());

            String localPath = downloadDetails.getLocalFilePath();

            OutputStream output = new FileOutputStream(localPath);

            byte data[] = new byte[1024];

            long total = 0;

            int count;

            while ((count = input.read(data)) != -1) {

                total += count;

                int progress = (int) ((total * 100) / lengthOfFile);

                sendProgress(progress, resultReceiver);

                output.write(data, 0, count);
            }

            output.flush();
            output.close();
            input.close();

            if (downloadDetails.isRequiresUnzip()) {

                String unzipDestination = downloadDetails.getUnzipAtFilePath();

                if(unzipDestination == null){

                    File file = new File(localPath);

                    unzipDestination = file.getParentFile().getAbsolutePath();
                }

                unzip(localPath, unzipDestination);
            }

            downloadCompleted(resultReceiver);

            if (downloadDetails.isDeleteZipAfterExtract()) {

                File file = new File(localPath);
                file.delete();
            }

        } catch (Exception e) {

            e.printStackTrace();

            downloadFailed(resultReceiver);
        }

    }

    public void sendProgress(int progress, ResultReceiver receiver) {

        Bundle progressBundle = new Bundle();
        progressBundle.putInt(FileDownloadService.DOWNLOAD_PROGRESS, progress);
        receiver.send(STATUS_OK, progressBundle);
    }

    public void downloadStarted(ResultReceiver resultReceiver) {

        Bundle progressBundle = new Bundle();
        progressBundle.putBoolean(FileDownloadService.DOWNLOAD_STARTED, true);
        resultReceiver.send(STATUS_OK, progressBundle);
    }

    public void downloadCompleted(ResultReceiver resultReceiver) {

        Bundle progressBundle = new Bundle();
        progressBundle.putBoolean(FileDownloadService.DOWNLOAD_COMPLETED, true);
        resultReceiver.send(STATUS_OK, progressBundle);
    }

    public void downloadFailed(ResultReceiver resultReceiver) {

        Bundle progressBundle = new Bundle();
        progressBundle.putBoolean(FileDownloadService.DOWNLOAD_FAILED, true);
        resultReceiver.send(STATUS_FAILED, progressBundle);
    }

    private void unzip(String zipFilePath, String unzipAtLocation) throws Exception {

        File archive = new File(zipFilePath);

        try {

            ZipFile zipfile = new ZipFile(archive);

            for (Enumeration e = zipfile.entries(); e.hasMoreElements(); ) {

                ZipEntry entry = (ZipEntry) e.nextElement();

                unzipEntry(zipfile, entry, unzipAtLocation);
            }

        } catch (Exception e) {

            Log.e("Unzip zip", "Unzip exception", e);
        }
    }

    private void unzipEntry(ZipFile zipfile, ZipEntry entry, String outputDir) throws IOException {

        if (entry.isDirectory()) {
            createDir(new File(outputDir, entry.getName()));
            return;
        }

        File outputFile = new File(outputDir, entry.getName());
        if (!outputFile.getParentFile().exists()) {
            createDir(outputFile.getParentFile());
        }

        Log.v("ZIP E", "Extracting: " + entry);

        InputStream zin = zipfile.getInputStream(entry);
        BufferedInputStream inputStream = new BufferedInputStream(zin);
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));

        try {

            //IOUtils.copy(inputStream, outputStream);

            try {

                for (int c = inputStream.read(); c != -1; c = inputStream.read()) {
                    outputStream.write(c);
                }

            } finally {

                outputStream.close();
            }

        } finally {
            outputStream.close();
            inputStream.close();
        }
    }

    private void createDir(File dir) {

        if (dir.exists()) {
            return;
        }

        Log.v("ZIP E", "Creating dir " + dir.getName());

        if (!dir.mkdirs()) {

            throw new RuntimeException("Can not create dir " + dir);
        }
    }

    public static class FileDownloader extends ResultReceiver {

        private DownloadRequest downloadDetails;

        private OnDownloadStatusListener onDownloadStatusListener;

        public static FileDownloader getInstance(DownloadRequest downloadDetails, OnDownloadStatusListener downloadStatusListener) {

            Handler handler = new Handler(Looper.getMainLooper());

            FileDownloader fileDownloader = new FileDownloader(handler);

            fileDownloader.downloadDetails = downloadDetails;

            fileDownloader.onDownloadStatusListener = downloadStatusListener;

            return fileDownloader;
        }

        public void download(Context context) {

            if (isOnline(context)) {

                Intent intent = new Intent(context, FileDownloadService.class);
                intent.putExtra(FileDownloadService.DOWNLOADER_RECEIVER, this);
                intent.putExtra(FileDownloadService.DOWNLOAD_DETAILS, downloadDetails);
                context.startService(intent);
            }
        }

        private FileDownloader(Handler handler) {

            super(handler);
        }

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {

            super.onReceiveResult(resultCode, resultData);

            if (onDownloadStatusListener == null) {

                return;
            }

            if (resultCode == FileDownloadService.STATUS_OK) {

                if (resultData.containsKey(FileDownloadService.DOWNLOAD_STARTED)
                        && resultData.getBoolean(FileDownloadService.DOWNLOAD_STARTED)) {

                    onDownloadStatusListener.onDownloadStarted();

                } else if (resultData.containsKey(FileDownloadService.DOWNLOAD_COMPLETED)
                        && resultData.getBoolean(FileDownloadService.DOWNLOAD_COMPLETED)) {

                    onDownloadStatusListener.onDownloadCompleted();

                } else if (resultData.containsKey(FileDownloadService.DOWNLOAD_PROGRESS)) {

                    int progress = resultData.getInt(FileDownloadService.DOWNLOAD_PROGRESS);
                    onDownloadStatusListener.onDownloadProgress(progress);

                }

            } else if (resultCode == FileDownloadService.STATUS_FAILED) {

                onDownloadStatusListener.onDownloadFailed();
            }
        }

        public DownloadRequest getDownloadDetails() {

            return downloadDetails;
        }

        public void setDownloadDetails(DownloadRequest downloadDetails) {

            this.downloadDetails = downloadDetails;
        }

        public OnDownloadStatusListener getOnDownloadStatusListener() {

            return onDownloadStatusListener;
        }

        public void setOnDownloadStatusListener(OnDownloadStatusListener onDownloadStatusListener) {

            this.onDownloadStatusListener = onDownloadStatusListener;
        }

    }

    public static interface OnDownloadStatusListener {

        void onDownloadStarted();

        void onDownloadCompleted();

        void onDownloadFailed();

        void onDownloadProgress(int progress);

    }

    public static class DownloadRequest implements Parcelable {

        private String tag;

        private boolean requiresUnzip;

        private String serverFilePath;

        private String localFilePath;

        private String unzipAtFilePath;

        private boolean deleteZipAfterExtract = true;

        public DownloadRequest(String serverFilePath, String localPath) {

            this.serverFilePath = serverFilePath;

            this.localFilePath = localPath;

            this.requiresUnzip = requiresUnzip;
        }

        protected DownloadRequest(Parcel in) {

            requiresUnzip = in.readByte() != 0x00;
            serverFilePath = in.readString();
            localFilePath = in.readString();
            unzipAtFilePath = in.readString();
            deleteZipAfterExtract = in.readByte() != 0x00;
        }

        @Override
        public int describeContents() {

            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {

            dest.writeByte((byte) (requiresUnzip ? 0x01 : 0x00));
            dest.writeString(serverFilePath);
            dest.writeString(localFilePath);
            dest.writeString(unzipAtFilePath);
            dest.writeByte((byte) (deleteZipAfterExtract ? 0x01 : 0x00));
        }

        @SuppressWarnings("unused")
        public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() {

            @Override
            public DownloadRequest createFromParcel(Parcel in) {

                return new DownloadRequest(in);
            }

            @Override
            public DownloadRequest[] newArray(int size) {

                return new DownloadRequest[size];
            }
        };

        public boolean isRequiresUnzip() {

            return requiresUnzip;
        }

        public void setRequiresUnzip(boolean requiresUnzip) {

            this.requiresUnzip = requiresUnzip;
        }

        public String getServerFilePath() {

            return serverFilePath;
        }

        public void setServerFilePath(String serverFilePath) {

            this.serverFilePath = serverFilePath;
        }

        public String getLocalFilePath() {

            return localFilePath;
        }

        public void setLocalFilePath(String localFilePath) {

            this.localFilePath = localFilePath;
        }

        public static Creator<DownloadRequest> getCreator() {

            return CREATOR;
        }

        public String getUnzipAtFilePath() {
            return unzipAtFilePath;
        }

        public void setUnzipAtFilePath(String unzipAtFilePath) {
            this.unzipAtFilePath = unzipAtFilePath;
        }

        public String getTag() {
            return tag;
        }

        public void setTag(String tag) {
            this.tag = tag;
        }

        public boolean isDeleteZipAfterExtract() {
            return deleteZipAfterExtract;
        }

        public void setDeleteZipAfterExtract(boolean deleteZipAfterExtract) {
            this.deleteZipAfterExtract = deleteZipAfterExtract;
        }
    }

    private static boolean isOnline(Context context) {

        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo netInfo = cm.getActiveNetworkInfo();

        if (netInfo != null
                && netInfo.isConnectedOrConnecting()
                && cm.getActiveNetworkInfo().isAvailable()
                && cm.getActiveNetworkInfo().isConnected()) {

            return true;
        }

        return false;
    }

}

Sample use case :

String serverFilePath = "http://www.colorado.edu/conflict/peace/download/peace_problem.ZIP";

String path = FileUtils.getDataDir(context).getAbsolutePath();

String fileName = "sample_download";
File file = new File(path, fileName);

String localPath = file.getAbsolutePath();
String unzipPath = FileUtils.getDataDir(context, "ExtractLoc").getAbsolutePath();

FileDownloadService.DownloadRequest downloadRequest = new FileDownloadService.DownloadRequest(serverFilePath, localPath);
downloadRequest.setRequiresUnzip(true);
downloadRequest.setDeleteZipAfterExtract(false);
downloadRequest.setUnzipAtFilePath(unzipPath);

FileDownloadService.OnDownloadStatusListener listener = new FileDownloadService.OnDownloadStatusListener() {

    @Override
    public void onDownloadStarted() {
    }

    @Override
    public void onDownloadCompleted() {
    }

    @Override
    public void onDownloadFailed() {
    }

    @Override
    public void onDownloadProgress(int progress) {
    }
};

FileDownloadService.FileDownloader downloader = FileDownloadService.FileDownloader.getInstance(downloadRequest, listener);
downloader.download(context);

Also you can use (if required) FileUtils.java

import android.content.Context;

import java.io.File;

public class FileUtils {

    public static File getDataDir(Context context) {

        String path = context.getFilesDir().getAbsolutePath() + "/SampleZip";

        File file = new File(path);

        if(!file.exists()) {

            file.mkdirs();
        }

        return file;
    }

    public static File getDataDir(Context context, String folder) {

        String path = context.getFilesDir().getAbsolutePath() + "/" + folder;

        File file = new File(path);

        if(!file.exists()) {

            file.mkdirs();
        }

        return file;
    }
}
Cooks answered 6/4, 2015 at 11:54 Comment(7)
it is not working for me can you helpFoggia
your code,but its not showing in sdcard and not able to downloadFoggia
can you paste full code please..i want to download zip file and store it in sdcardFoggia
@Foggia No one can write FULL CODE for you. You need to learn debugging.Cooks
i did all that permissionFoggia
Working perfectly!Cafard
excellent Working perfectly!!!Argumentation
S
5

As JoxTraex said: the error is really obvious.

In UnzipManager line 129 you try to open a file that is not there. Thats why you get a FileNotFoundException. You should check your zip file if it is a correct one and can be extracted correctly on your PC.

Try to debug, too. Add a break point on that line and let the application debug and watch what happens there when the specific file location appears.

Septuplet answered 17/2, 2012 at 10:14 Comment(5)
Who ever down voted: Without a comment, the down vote is nonsense. Thanks for not taking part in the community!Septuplet
Your code worked fine. I just added the permission to the Manifest File. Its a great peace of code. Thanks for sharing.Diffract
@BadLuckBrian spammer? Which code? Which permission?Septuplet
The code in the question. It worked fine for me after i gave the android.permission.WRITE_EXTERNAL_STORAGE permission.Diffract
@BadLuckBrian The code in the question is not my code. I am taking back the "spammer" but I was highly confused by your comment :)Septuplet
B
2

Don't Delete the file if exists (because the files will be overwritten) or instantiate innerFile again.

if (innerFile.exists()) {
         Log.d("DEBUG",
               "The Entry already exits!, so deleting..");
         innerFile.delete();
}

//Instantiate Again
innerFile = new File(innerFileName);

Deleting innerFile you lose the file and when trying to create directory using innerFile causes the FileNotFoundException.

Balling answered 30/1, 2013 at 22:12 Comment(0)
R
1

This is the final code using the performance improvement answer, it decompressed a 23 MB file into a 130 MB folder in exactly 1 minute:

public class Decompress {
private String _zipFile;
private String _location;

public Decompress(String zipFile, String location) {
    _zipFile = zipFile;
    _location = location;

    _dirChecker("");
}

public void unzip() {
    try  {
        FileInputStream fin = new FileInputStream(_zipFile);
        ZipInputStream zin = new ZipInputStream(fin);

        byte b[] = new byte[1024];

        ZipEntry ze = null;
        while ((ze = zin.getNextEntry()) != null) {
            Log.v("Decompress", "Unzipping " + ze.getName());

            if(ze.isDirectory()) {
                _dirChecker(ze.getName());
            } else {
                FileOutputStream fout = new FileOutputStream(_location + ze.getName());

                BufferedInputStream in = new BufferedInputStream(zin);
                BufferedOutputStream out = new BufferedOutputStream(fout);

                int n;
                while ((n = in.read(b,0,1024)) >= 0) {
                    out.write(b,0,n);
                }

                zin.closeEntry();
                out.close();
            }

        }
        zin.close();
    } catch(Exception e) {
        Log.e("Decompress", "unzip", e);
    }

}

private void _dirChecker(String dir) {
    File f = new File(_location + dir);

    if(!f.isDirectory()) {
        f.mkdirs();
    }
}}
Rosel answered 2/6, 2015 at 20:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.