在Android下载和提取Zip文件

我的应用程序是从服务器下载zip文件,并提取这个zip文件,并将文件保存到SD卡,但问题是,如果我正在下载4-5 MB的zip文件并解压缩,这是工作好,但如果我下载30-35 MB 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) 

Solutions Collecting From Web of "在Android下载和提取Zip文件"

我写了一个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.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(); 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() { subscriber.onNext(String.valueOf(0)); } @Override public void onDownloadCompleted() { subscriber.onNext(String.valueOf(100)); } @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; } } 

正如JoxTraex所说:错误真的很明显。

UnzipManager行129中,您尝试打开不在那里的文件。 这就是为什么你得到一个FileNotFoundException 。 你应该检查你的zip文件,如果它是一个正确的,可以在你的电脑上正确提取。

也尝试debugging。 在该行上添加一个断点,并让应用程序debugging并观察特定文件位置出现时发生的情况。

如果存在(因为文件将被覆盖)或者再次实例化innerFile,请不要删除文件。

 if (innerFile.exists()) { Log.d("DEBUG", "The Entry already exits!, so deleting.."); innerFile.delete(); } //Instantiate Again innerFile = new File(innerFileName); 

删除innerFile会丢失文件,并且在使用innerFile尝试创build目录时会导致FileNotFoundException。

这是使用性能改进答案的最终代码,它在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(); } }}