web-dev-qa-db-ja.com

AndroidでZipファイルをダウンロードして解凍します

私のアプリケーションはZipファイルをサーバーからダウンロードしてこのZipファイルを抽出し、SDカードにファイルを保存しますが、問題は4〜5MBのZipファイルをダウンロードして抽出した場合、これはうまく機能していますが、30〜35MBをダウンロードしている場合Zipファイルを使用すると、エラーが発生します。英語のコミュニケーションがうまくいかないのでごめんなさい。

以下は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エラーは次のとおりです-

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

私はIntentServiceを書きました。これは両方のことを進行と一緒に投与します:

次のサービスクラスをアプリケーションに追加します(アプリのマニフェストファイルでも宣言します):

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

}

サンプルの使用例:

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

また、(必要な場合)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;
    }
}
11
Vaibhav Jani

JoxTraexが言ったように:エラーは本当に明らかです。

UnzipManager行129に、存在しないファイルを開こうとしました。それがFileNotFoundExceptionを取得する理由です。 Zipファイルが正しいファイルであり、PCで正しく抽出できる場合は、Zipファイルを確認する必要があります。

デバッグも試してください。その行にブレークポイントを追加し、アプリケーションにデバッグさせて、特定のファイルの場所が表示されたときにそこで何が起こるかを見てみましょう。

5
WarrenFaith

存在する場合はファイルを削除しないでください(ファイルが上書きされるため)、またはinnerFileを再度インスタンス化します。

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

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

InnerFileを削除するとファイルが失われ、innerFileを使用してディレクトリを作成しようとするとFileNotFoundExceptionが発生します。

2
N20084753

これは、 パフォーマンス改善の答え を使用した最終コードです。正確に1分で23 MBのファイルを130 MBのフォルダーに解凍しました。

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