1. 程式人生 > >Android開發之Zip下載解壓

Android開發之Zip下載解壓

本篇部落格為需求而發燒,若有雷同需求code拿走不謝。

需求如下:點選Item,從伺服器下載zip包到本地資料夾並解壓,解壓後的圖片檔案全部查詢出來,用於介面預覽

沒有強制每次都下載zip包保持最新,如果有需要FileDownload有函式支援,亦可以自行新增解壓後自動刪除zip包

流程:

  • 下載zip包

  • 解壓zip包

  • 查詢指定檔案格式的檔案路徑集合(.jpg為例)

檔案下載推薦開源庫FileDownloader

compile 'com.liulishuo.filedownloader:library:1.7.2'

接入專案首先Application初始化

FileDownloader.setup(Context)

需求是單任務下載zip,呼叫示例如下

FileDownloader.getImpl().create(url)
        .setPath(path)
        .setListener(new FileDownloadListener() {
            @Override
            protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
            }

            @Override
protected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) { } @Override protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected
void blockComplete(BaseDownloadTask task) { } @Override protected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) { } @Override protected void completed(BaseDownloadTask task) { } @Override protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) { } @Override protected void error(BaseDownloadTask task, Throwable e) { } @Override protected void warn(BaseDownloadTask task) { } }).start();

是否支援強制重新下載zip包

 setForceReDownload(false)

檔案下載完成後開始解壓,這裡推薦使用開源庫zt-zip

解壓zip但不需要過濾匹配是否含有指定檔案,所以只需要傳入檔案路徑和解壓目錄

 private void unPackage(String zipPath,String outputDir){
        ZipUtil.unpack(new File(zipPath), new File(outputDir));
    }

解壓後遍解壓目錄下的.jpg檔案

    /**
     * 查詢解壓目錄下的檔案,並過濾檔案格式返回路徑集合
     * @hide
     * @param outputDir
     * @return
     */
    private ArrayList<String> queryUnPackageOutputDir(String outputDir){
            ArrayList<String> arrayList = new ArrayList<>();
            File file = new File(outputDir);
            File[] subFile = file.listFiles();
            for (int iFileLength = 0; iFileLength < subFile.length; iFileLength++) {
                if (!subFile[iFileLength].isDirectory()) {
                    String filename = subFile[iFileLength].getAbsolutePath();
                    if (filename.trim().toLowerCase().endsWith(".jpg")) {
                        arrayList.add(filename);
                    }
                }
            }
            return arrayList;
    }

下面提供一個Helper類以及程式碼呼叫示例

import android.app.Activity;
import android.os.Environment;
import android.util.Log;

import com.liulishuo.filedownloader.BaseDownloadTask;
import com.liulishuo.filedownloader.FileDownloadListener;
import com.liulishuo.filedownloader.FileDownloader;

import org.zeroturnaround.zip.ZipUtil;

import java.io.File;
import java.util.ArrayList;

/**
 * Created by idea on 2018/3/26.
 */

public class ZipHelper {

    public static final String TEST_ZIP_URL = "用於測試的zip下載地址,自行完善";

    /***
     *
     * Unpacking
     *
     * Check if an entry exists in a ZIP archive
     * boolean exists = ZipUtil.containsEntry(new File("/tmp/demo.zip"), "foo.txt");
     *
     * Extract an entry from a ZIP archive into a byte array
     * byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt");
     *
     * Extract an entry from a ZIP archive with a specific Charset into a byte array
     * byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", Charset.forName("IBM437"));
     *
     * Extract an entry from a ZIP archive into file system
     * ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", new File("/tmp/bar.txt"));
     *
     * Extract a ZIP archive
     * ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"));
     *
     * Extract a ZIP archive which becomes a directory
     * ZipUtil.explode(new File("/tmp/demo.zip"));
     *
     * Extract a directory from a ZIP archive including the directory name
     * ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
     *          public String map(String name) {
     *              return name.startsWith("doc/") ? name : null;
     *          }
     *  });
     *
     * Extract a directory from a ZIP archive excluding the directory name
     * final String prefix = "doc/";
     * ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
     *    public String map(String name) {
     *      return name.startsWith(prefix) ? name.substring(prefix.length()) : name;
     *    }
     * });
     *
     * Extract files from a ZIP archive that match a name pattern
     *
     * ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
     *    public String map(String name) {
     *          if (name.contains("/doc")) {
     *             return name;
     *          }else {
     *             // returning null from the map method will disregard the entry
     *             return null;
     *          }
     *    }
     * });
     *
     * Print .class entry names in a ZIP archive
     * ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipInfoCallback() {
     *        public void process(ZipEntry zipEntry) throws IOException {
     *             if (zipEntry.getName().endsWith(".class"))
     *                 System.out.println("Found " + zipEntry.getName());
     *              }
     * });
     *
     * Print .txt entries in a ZIP archive (uses IoUtils from Commons IO)
     * ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipEntryCallback() {
     *            public void process(InputStream in, ZipEntry zipEntry) throws IOException {
     *                  if (zipEntry.getName().endsWith(".txt")) {
     *                     System.out.println("Found " + zipEntry.getName());
     *                     IOUtils.copy(in, System.out);
     *                  }
     *            }
     * });
     *
     *  @hide
     * 解壓zip檔案
     *
     */
    private void unPackage(String zipPath,String outputDir){
        ZipUtil.unpack(new File(zipPath), new File(outputDir));
    }

    /**
     * 查詢解壓目錄下的檔案,並過濾檔案格式返回路徑集合
     * @hide
     * @param outputDir
     * @return
     */
    private ArrayList<String> queryUnPackageOutputDir(String outputDir){
            ArrayList<String> arrayList = new ArrayList<>();
            File file = new File(outputDir);
            File[] subFile = file.listFiles();
            for (int iFileLength = 0; iFileLength < subFile.length; iFileLength++) {
                if (!subFile[iFileLength].isDirectory()) {
                    String filename = subFile[iFileLength].getAbsolutePath();
                    if (filename.trim().toLowerCase().endsWith(".jpg")) {
                        arrayList.add(filename);
                    }
                }
            }
            return arrayList;
    }

    /**
     * 判斷指定目錄是否下載過zip檔案
     * @param zipName zip檔名稱
     * @param zipCachePath 資料夾
     * @hide
     * @return
     */
    private boolean containsZipFile(String zipCachePath,String zipName){
        boolean result = false;
        File file = new File(zipCachePath);
        if (file.exists()) {
            File zipFile = new File(zipCachePath+"/"+zipName);
            if(zipFile.exists()){
                result = true;
            } else{
                result = false;
            }
        } else {
            file.mkdir();
        }
        return result;
    }

    /**
     * 下載zip檔案
     * @hide
     * @param url
     * @param zipPath
     */
    private void downloadZipFile(String url, String zipPath,final OnDownloadZipListener onDownloadZipListener){
        FileDownloader.getImpl().create(url)
                .setPath(zipPath)
                .setForceReDownload(false)
                .setListener(new FileDownloadListener() {
                    @Override
                    protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
                    }

                    @Override
                    protected void connected(BaseDownloadTask task, String etag, boolean isContinue, int soFarBytes, int totalBytes) {
                    }

                    @Override
                    protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
                    }

                    @Override
                    protected void blockComplete(BaseDownloadTask task) {
                    }

                    @Override
                    protected void retry(final BaseDownloadTask task, final Throwable ex, final int retryingTimes, final int soFarBytes) {
                    }

                    @Override
                    protected void completed(BaseDownloadTask task) {
                        onDownloadZipListener.onComplete();
                    }

                    @Override
                    protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) {
                    }

                    @Override
                    protected void error(BaseDownloadTask task, Throwable e) {
                        onDownloadZipListener.onError();
                    }

                    @Override
                    protected void warn(BaseDownloadTask task) {
                    }
                }).start();
    }

    /**
     * 每載入完成一張圖片就立即刪除檔案
     * @param path
     */
    public void deleteFile(String path){
        File file = new File(path);
        if(file.isFile()&&file.exists()){
            file.delete();
        }
    }

    /**
     * 刪除解壓檔案
     */
    public void clearOutputDir(){
        String dir = "/iot.monitoring.zip.output";
        File outputDirFile = new File(Environment.getExternalStorageDirectory(), dir);
            File[] listFiles = outputDirFile.listFiles();
            if (outputDirFile.exists()&&listFiles!=null&&listFiles.length>0) {
                for(int i = 0;i<listFiles.length;i++){
                    listFiles[i].delete();
                }
        }
    }

    /**
     * 下載zip檔案
     * @hide
     * @param url 下載路徑
     * @param zipCachePath 快取目錄
     * @param outputDir 解壓目錄
     */
    private void doBackground(final Activity activity, final String url, final String zipCachePath, final String outputDir, final UnPackageImageListener unPackageImageListener){

                //阿里雲 zip下路路徑格式如下: http//xxxxxx.xx.xx/xxx/xxx.zip?xxxxxx
                int index = url.indexOf("?");
                final String [] array = url.substring(0,index).split("/");
                downloadZipFile(url, zipCachePath + "/" + array[array.length - 1], new OnDownloadZipListener() {
                    @Override
                    public void onError() {
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                unPackageImageListener.onError();
                            }
                        });
                    }

                    @Override
                    public void onComplete() {
                        unPackage(zipCachePath+"/"+array[array.length-1],outputDir);
                        final ArrayList<String> collection = queryUnPackageOutputDir(outputDir);
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                unPackageImageListener.onSuccess(collection);
                            }
                        });
                    }
                });

    }

    /**
     * 下載zip圖片集合並解壓到目錄,獲取查詢結果
     * @param activity
     * @param url
     * @param unPackageImageListener
     */
    public void queryImageCollection(final Activity activity, final String url, final UnPackageImageListener unPackageImageListener){

        String dir = "/idea.analyzesystem.zip";
        File zipCachePathDir = new File(Environment.getExternalStorageDirectory(), dir);
        if (!zipCachePathDir.exists()) {
            zipCachePathDir.mkdir();
        }
        dir = "/idea.analyzesystem.zip.output";
        File outputDir = new File(Environment.getExternalStorageDirectory(), dir);
        if (!outputDir.exists()) {
            outputDir.mkdir();
        }

        clearOutputDir();

        String zipCachePath = zipCachePathDir.getAbsolutePath();
        String outputDirPath = outputDir.getAbsolutePath();
        doBackground(activity,url,zipCachePath,outputDirPath,unPackageImageListener);

    }

    public interface OnDownloadZipListener{
        void onError();

        void onComplete();
    }

    public interface UnPackageImageListener{
        void onError();

        void onSuccess(ArrayList<String> result);
    }

}

 new ZipHelper().queryImageCollection(getActivity(),url,new ZipHelper.UnPackageImageListener() {

         @Override
         public void onError() {

         }

         @Override
         public void onSuccess(ArrayList<String> result) {

         }
   });