web-dev-qa-db-fra.com

Télécharger et extraire le fichier Zip dans Android

Mon application télécharge le fichier Zip du serveur et extrait ce fichier Zip et enregistre les fichiers sur une carte SD, mais le problème est que si je télécharge des fichiers Zip 4-5 Mo et que je l'extrais, cela fonctionne bien, mais si je télécharge 30-35 Mo Fichier Zip cela me donnera une erreur, désolé pour ma mauvaise communication en anglais.

Voici le code à télécharger et décompresser le fichier Zip: -

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)
27
Dipak Keshariya

J'ai écrit une IntentService qui associe les progrès et les progrès:

Ajouter la classe de service suivante à votre application (le déclarer également dans le fichier manifeste de votre application):  

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

}

Exemple de cas d'utilisation:

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

Aussi, vous pouvez utiliser (si nécessaire) 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;
    }
}
9
Vaibhav Jani

Comme l'a dit JoxTraex: l'erreur est vraiment évidente.

Dans UnzipManager ligne 129, vous essayez d'ouvrir un fichier qui n'y est pas. C'est pourquoi vous obtenez un FileNotFoundException. Vous devriez vérifier votre fichier Zip s'il est correct et s'il peut être extrait correctement sur votre PC.

Essayez de déboguer aussi. Ajoutez un point d'arrêt sur cette ligne et laissez l'application déboguer et observez ce qui s'y passe lorsque l'emplacement du fichier spécifique apparaît.

5
WarrenFaith

Ne supprimez pas le fichier s'il existe (car les fichiers seront écrasés) ou instanciez à nouveau innerFile. 

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

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

Si vous supprimez innerFile, vous perdez le fichier. Lorsque vous essayez de créer un répertoire à l’aide de innerFile, l’exception FileNotFoundException apparaît.

2
N20084753

Ceci est le code final qui utilise la réponse amélioration des performances , il a décompressé un fichier de 23 Mo dans un dossier de 130 Mo en 1 minute exactement:

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