Android - 解压缩文件夹?

Posted

技术标签:

【中文标题】Android - 解压缩文件夹?【英文标题】:Android - Unzip a folder? 【发布时间】:2011-02-17 11:38:04 【问题描述】:

我的 SD 卡上有一个 zip 文件夹,如何解压缩该文件夹(在我的应用程序代码中)?

【问题讨论】:

我想你已经添加了访问外部存储的权限? 【参考方案1】:

我正在使用 Beginner 方法的修改版本,它扩展了 AsyncTask 并可以更新主线程上的观察者。逐字节压缩非常慢,应该避免。相反,一种更有效的方法是将大量数据复制到输出流中。

package com.blarg.webviewscroller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Observable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.commons.io.IOUtils;

import android.os.AsyncTask;
import android.util.Log;

public class UnZipper extends Observable 

    private static final String TAG = "UnZip";
    private String mFileName, mFilePath, mDestinationPath;

    public UnZipper (String fileName, String filePath, String destinationPath) 
        mFileName = fileName;
        mFilePath = filePath;
        mDestinationPath = destinationPath;
    

    public String getFileName () 
        return mFileName;
    

    public String getFilePath() 
        return mFilePath;
    

    public String getDestinationPath () 
        return mDestinationPath;
    

    public void unzip () 
        String fullPath = mFilePath + "/" + mFileName + ".zip";
        Log.d(TAG, "unzipping " + mFileName + " to " + mDestinationPath);
        new UnZipTask().execute(fullPath, mDestinationPath);
    

    private class UnZipTask extends AsyncTask<String, Void, Boolean> 

        @SuppressWarnings("rawtypes")
        @Override
        protected Boolean doInBackground(String... params) 
            String filePath = params[0];
            String destinationPath = params[1];

            File archive = new File(filePath);
            try 
                ZipFile zipfile = new ZipFile(archive);
                for (Enumeration e = zipfile.entries(); e.hasMoreElements();) 
                    ZipEntry entry = (ZipEntry) e.nextElement();
                    unzipEntry(zipfile, entry, destinationPath);
                
             catch (Exception e) 
                Log.e(TAG, "Error while extracting file " + archive, e);
                return false;
            

            return true;
        

        @Override
        protected void onPostExecute(Boolean result) 
            setChanged();
            notifyObservers();
        

        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(TAG, "Extracting: " + entry);
            BufferedInputStream inputStream = new BufferedInputStream(zipfile.getInputStream(entry));
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));

            try 
                IOUtils.copy(inputStream, outputStream);
             finally 
                outputStream.close();
                inputStream.close();
            
        

        private void createDir(File dir) 
            if (dir.exists()) 
                return;
            
            Log.v(TAG, "Creating dir " + dir.getName());
            if (!dir.mkdirs()) 
                throw new RuntimeException("Can not create dir " + dir);
            
        
    
 

被实现Observer的类使用,如:

private void unzipWebFile(String filename) 
    String unzipLocation = getExternalFilesDir(null) + "/unzipped";
    String filePath = Environment.getExternalStorageDirectory().toString();

    UnZipper unzipper = new UnZipper(filename, filePath, unzipLocation);
    unzipper.addObserver(this);
    unzipper.unzip();

解压缩完成后,您的观察者将收到update(Observable observable, Object data) 回调。

【讨论】:

从哪里获得 IOUtils 以及如何安装它? IOUtils 是 Apache Commons IO 的一部分 commons.apache.org/proper/commons-io【参考方案2】:
static Handler myHandler;
ProgressDialog myProgress;

public void unzipFile(File zipfile) 
        myProgress = ProgressDialog.show(getContext(), "Extract Zip",
                        "Extracting Files...", true, false);
        File zipFile = zipfile;
        String directory = null;
        directory = zipFile.getParent();
        directory = directory + "/";
        myHandler = new Handler() 

                @Override
                public void handleMessage(Message msg) 
                        // process incoming messages here
                        switch (msg.what) 
                        case 0:
                                // update progress bar
                                myProgress.setMessage("" + (String) msg.obj);
                                break;
                        case 1:
                                myProgress.cancel();
                                Toast toast = Toast.makeText(getContext(),
                                                "Zip extracted successfully", 
Toast.LENGTH_SHORT);
                                toast.show();
                                provider.refresh();
                                break;
                        case 2:
                                myProgress.cancel();
                                break;
                        
                        super.handleMessage(msg);
                

        ;
        Thread workthread = new Thread(new UnZip(zipFile, directory));
        workthread.start();


public class UnZip implements Runnable 

        File archive;
        String outputDir;

        public UnZip(File ziparchive, String directory) 
                archive = ziparchive;
                outputDir = directory;
        

        public void log(String log) 
                Log.v("unzip", log);
        

        @SuppressWarnings("unchecked")
        public void run() 
                Message msg;
                try 
                        ZipFile zipfile = new ZipFile(archive);
                        for (Enumeration e = zipfile.entries(); 
e.hasMoreElements();) 
                                ZipEntry entry = (ZipEntry) e.nextElement();
                                msg = new Message();
                                msg.what = 0;
                                msg.obj = "Extracting " + entry.getName();
                                myHandler.sendMessage(msg);
                                unzipEntry(zipfile, entry, outputDir);
                        
                 catch (Exception e) 
                        log("Error while extracting file " + archive);
                
                msg = new Message();
                msg.what = 1;
                myHandler.sendMessage(msg);
        

        @SuppressWarnings("unchecked")
        public void unzipArchive(File archive, String outputDir) 
                try 
                        ZipFile zipfile = new ZipFile(archive);
                        for (Enumeration e = zipfile.entries(); 
e.hasMoreElements();) 
                                ZipEntry entry = (ZipEntry) e.nextElement();
                                unzipEntry(zipfile, entry, outputDir);
                        
                 catch (Exception e) 
                        log("Error while extracting file " + archive);
                
        

        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("Extracting: " + entry);
                BufferedInputStream inputStream = new 
BufferedInputStream(zipfile
                                .getInputStream(entry));
                BufferedOutputStream outputStream = new BufferedOutputStream(
                                new FileOutputStream(outputFile));

                try 
                        IOUtils.copy(inputStream, outputStream);
                 finally 
                        outputStream.close();
                        inputStream.close();
                
        

        private void createDir(File dir) 
                log("Creating dir " + dir.getName());
                if (!dir.mkdirs())
                        throw new RuntimeException("Can not create dir " + dir);
        

这对我有用,谢谢大家

【讨论】:

handleMessage() 中的情况 2 是什么?我没有看到任何 msg.what = 2。 它对我有用,但是如果我从服务器下载 zip 文件然后解压缩它,它会显示错误 java.util.zip.ZipException: EOCD not found,对它有任何想法 【参考方案3】:

@rich.e 答案只是“插件”:

doInBackground() 中,在遍历 ZipEtries 之后,您应该关闭该文件,因为有时您希望在解压缩后删除该文件,如果文件未关闭则会引发异常:

try 
        ZipFile zipfile = new ZipFile(archive);
        int entries = zipfile.size();
        int total = 0;
        if(onZipListener != null)
            onZipListener.onUncompressStart(archive);

        for (Enumeration<?> e = zipfile.entries(); e.hasMoreElements();) 
            ZipEntry entry = (ZipEntry) e.nextElement();
            if(onZipListener != null)
                onZipListener.onUncompressProgress(archive, (int) (total++ * 100 / entries));
            unzipEntry(zipfile, entry, path);
        
        zipfile.close();
     catch (Exception e) 
        e.printStackTrace();
    

【讨论】:

以上是关于Android - 解压缩文件夹?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 中以编程方式解压缩文件?

在 Android 应用程序中解压缩 sd 卡上的压缩文件

Android Zip解压缩目录穿越导致文件覆盖漏洞

解压缩来自服务器的 zip 文件,而不在 ios swift 中本地保存,类似于 android 的操作?

Android Zip解压缩目录穿越导致文件覆盖漏洞

Android Zip解压缩目录穿越导致文件覆盖漏洞