1. 程式人生 > >AntZipUtils【基於Ant的Zip壓縮解壓縮工具類】

AntZipUtils【基於Ant的Zip壓縮解壓縮工具類】

odi lose 子目錄 https unzip jar包下載 eno details ++

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

前言

Android 壓縮解壓zip文件一般分為兩種方式:

  • 基於JDK的Zip壓縮工具類

  該版本存在問題:壓縮時如果目錄或文件名含有中文,壓縮後會變成亂碼;

  使用Java的zip包可以進行簡單的文件壓縮和解壓縮處理時,但是遇到包含中文漢字目錄或者包含多層子目錄的復雜目錄結構時,容易出現各種各樣的問題。

  • 基於Ant的Zip壓縮工具類

  需要第三方JAR包:Apache的ant.jar;

  解決了上面存在的問題。

效果圖

技術分享

代碼分析

常用的方法:

壓縮文件:

makeZip(String[] srcFilePaths, String zipPath)

解壓文件:

unZip(String zipFilePath, String targetDirPath)

使用步驟

一、項目組織結構圖

技術分享

註意事項:

1、 導入類文件後需要change包名以及重新import R文件路徑

2、 Values目錄下的文件(strings.xml、dimens.xml、colors.xml等),如果項目中存在,則復制裏面的內容,不要整個覆蓋

二、導入步驟

將相關jar包復制到項目的libs目錄下並同步Gradle File

jar包下載地址:鏈接:http://pan.baidu.com/s/1c1DlLc8 密碼:8aq7

技術分享

將AntZipUtils文件復制到項目中

技術分享
package com.why.project.antziputilsdemo.utils;

import android.util.Log;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipException; /** * @Create By HaiyuKing * @Used 基於Ant的Zip壓縮工具類 * @參考資料 http://yunzhu.iteye.com/blog/1480293 * http://www.cnblogs.com/wainiwann/archive/2013/07/17/3196196.html * http://blog.csdn.net/growing_tree/article/details/46009813 * http://www.jb51.net/article/69773.htm */ public class AntZipUtils { public static final String ENCODING_DEFAULT = "UTF-8"; public static final int BUFFER_SIZE_DIFAULT = 1024; /**生成ZIP壓縮包【建議異步執行】 * @param srcFilePaths - 要壓縮的文件路徑字符串數組【如果壓縮一個文件夾,則只需要把文件夾目錄放到一個數組中即可】 * @param zipPath - 生成的Zip路徑*/ public static void makeZip(String[] srcFilePaths, String zipPath)throws Exception { makeZip(srcFilePaths, zipPath, ENCODING_DEFAULT); } /**生成ZIP壓縮包【建議異步執行】 * @param srcFilePaths - 要壓縮的文件路徑字符串數組 * @param zipPath - 生成的Zip路徑 * @param encoding - 編碼格式*/ public static void makeZip(String[] srcFilePaths, String zipPath,String encoding) throws Exception { File[] inFiles = new File[srcFilePaths.length]; for (int i = 0; i < srcFilePaths.length; i++) { inFiles[i] = new File(srcFilePaths[i]); } makeZip(inFiles, zipPath, encoding); } /**生成ZIP壓縮包【建議異步執行】 * @param srcFiles - 要壓縮的文件數組 * @param zipPath - 生成的Zip路徑*/ public static void makeZip(File[] srcFiles, String zipPath) throws Exception { makeZip(srcFiles, zipPath, ENCODING_DEFAULT); } /**生成ZIP壓縮包【建議異步執行】 * @param srcFiles - 要壓縮的文件數組 * @param zipPath - 生成的Zip路徑 * @param encoding - 編碼格式*/ public static void makeZip(File[] srcFiles, String zipPath, String encoding) throws Exception { ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipPath))); zipOut.setEncoding(encoding); for (int i = 0; i < srcFiles.length; i++) { File file = srcFiles[i]; doZipFile(zipOut, file, file.getParent()); } zipOut.flush(); zipOut.close(); } private static void doZipFile(ZipOutputStream zipOut, File file, String dirPath) throws FileNotFoundException, IOException { if (file.isFile()) { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); String zipName = file.getPath().substring(dirPath.length()); while (zipName.charAt(0) == ‘\\‘ || zipName.charAt(0) == ‘/‘) { zipName = zipName.substring(1); } ZipEntry entry = new ZipEntry(zipName); zipOut.putNextEntry(entry); byte[] buff = new byte[BUFFER_SIZE_DIFAULT]; int size; while ((size = bis.read(buff, 0, buff.length)) != -1) { zipOut.write(buff, 0, size); } zipOut.closeEntry(); bis.close(); } else { File[] subFiles = file.listFiles(); for (File subFile : subFiles) { doZipFile(zipOut, subFile, dirPath); } } } /**解壓ZIP包【建議異步執行】 * @param zipFilePath ZIP包的路徑 * @param targetDirPath 指定的解壓縮文件夾地址 */ public static void unZip(String zipFilePath, String targetDirPath)throws IOException,Exception { unZip(new File(zipFilePath), targetDirPath); } /**解壓ZIP包【建議異步執行】 * @param zipFile ZIP包的文件 * @param targetDirPath 指定的解壓縮目錄地址 */ public static void unZip(File zipFile, String targetDirPath) throws IOException,Exception { //先刪除,後添加 if (new File(targetDirPath).exists()) { new File(targetDirPath).delete(); } new File(targetDirPath).mkdirs(); ZipFile zip = new ZipFile(zipFile); Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zip.getEntries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); if (zipEntry.isDirectory()) { // TODO } else { String zipEntryName = zipEntry.getName(); if(zipEntryName.contains("../")){//2016-08-25 throw new Exception("unsecurity zipfile"); }else{ if (zipEntryName.indexOf(File.separator) > 0) { String zipEntryDir = zipEntryName.substring(0, zipEntryName.lastIndexOf(File.separator) + 1); String unzipFileDir = targetDirPath + File.separator + zipEntryDir; File unzipFileDirFile = new File(unzipFileDir); if (!unzipFileDirFile.exists()) { unzipFileDirFile.mkdirs(); } } InputStream is = zip.getInputStream(zipEntry); FileOutputStream fos = new FileOutputStream(new File(targetDirPath + File.separator + zipEntryName)); byte[] buff = new byte[BUFFER_SIZE_DIFAULT]; int size; while ((size = is.read(buff)) > 0) { fos.write(buff, 0, size); } fos.flush(); fos.close(); is.close(); } } } } /** * 使用Apache工具包解壓縮zip文件 【使用Java的zip包可以進行簡單的文件壓縮和解壓縮處理時,但是遇到包含中文漢字目錄或者包含多層子目錄的復雜目錄結構時,容易出現各種各樣的問題。】 * @param sourceFilePath 指定的解壓縮文件地址 * @param targetDirPath 指定的解壓縮目錄地址 * @throws IOException * @throws FileNotFoundException * @throws ZipException */ public static void uncompressFile(String sourceFilePath, String targetDirPath)throws IOException, FileNotFoundException, ZipException,Exception{ BufferedInputStream bis; ZipFile zf = new ZipFile(sourceFilePath, "GBK"); Enumeration entries = zf.getEntries(); while (entries.hasMoreElements()){ ZipEntry ze = (ZipEntry) entries.nextElement(); String entryName = ze.getName(); if(entryName.contains("../")){//2016-08-25 throw new Exception("unsecurity zipfile"); }else{ String path = targetDirPath + File.separator + entryName; Log.d("AntZipUtils", "path="+path); if (ze.isDirectory()){ Log.d("AntZipUtils","正在創建解壓目錄 - " + entryName); File decompressDirFile = new File(path); if (!decompressDirFile.exists()){ decompressDirFile.mkdirs(); } } else{ Log.d("AntZipUtils","正在創建解壓文件 - " + entryName); String fileDir = path.substring(0, path.lastIndexOf(File.separator)); Log.d("AntZipUtils", "fileDir="+fileDir); File fileDirFile = new File(fileDir); if (!fileDirFile.exists()){ fileDirFile.mkdirs(); } BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetDirPath + File.separator + entryName)); bis = new BufferedInputStream(zf.getInputStream(ze)); byte[] readContent = new byte[1024]; int readCount = bis.read(readContent); while (readCount != -1){ bos.write(readContent, 0, readCount); readCount = bis.read(readContent); } bos.close(); } } } zf.close(); } }
AntZipUtils.java

在AndroidManifest.xml中添加權限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.why.project.antziputilsdemo">

    <!-- ======================(AntZipUtils)========================== -->
    <!-- 在SD卡中創建與刪除文件權限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <!-- 向SD卡寫入數據權限 -->
    <uses-permission android:name="android.permission.REORDER_TASKS"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

添加運行時權限的處理(本demo中采用的是修改targetSDKVersion=22)

三、使用方法

package com.why.project.antziputilsdemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.why.project.antziputilsdemo.utils.AntZipUtils;

public class MainActivity extends AppCompatActivity {

    private Button btn_makeZip;
    private Button btn_unZip;
    private TextView tv_show;

    private MakeZipTask makeZipTask;//生成zip文件的異步請求類
    private UnZipTask unZipTask;//解壓zip文件的異步請求類

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initViews();
        initEvents();
    }

    @Override
    public void onPause() {
        super.onPause();
        //cancel方法只是將對應的AsyncTask標記為cancel狀態,並不是真正的取消線程的執行,在Java中並不能粗暴的停止線程,只能等線程執行完之後做後面的操作
        if (makeZipTask != null && makeZipTask.getStatus() == AsyncTask.Status.RUNNING) {
            makeZipTask.cancel(true);
        }
        if (unZipTask != null && unZipTask.getStatus() == AsyncTask.Status.RUNNING) {
            unZipTask.cancel(true);
        }
    }

    private void initViews() {
        btn_makeZip = (Button) findViewById(R.id.btn_makeZip);
        btn_unZip = (Button) findViewById(R.id.btn_unZip);

        tv_show = (TextView) findViewById(R.id.tv_show);
    }

    private void initEvents() {
        btn_makeZip.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //生成ZIP壓縮包【建議異步執行】
                makeZipTask = new MakeZipTask();
                makeZipTask.execute();
            }
        });

        btn_unZip.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //解壓ZIP包【建議異步執行】
                unZipTask = new UnZipTask();
                unZipTask.execute();

            }
        });
    }


    /**
     * 壓縮文件的異步請求任務
     *
     */
    public class MakeZipTask extends AsyncTask<String, Void, String>{

        @Override
        protected void onPreExecute() {
            //顯示進度對話框
            //showProgressDialog("");
            tv_show.setText("正在壓縮...");
        }

        @Override
        protected String doInBackground(String... params) {
            String data = "";
            if(! isCancelled()){
                try {
                    String[] srcFilePaths = new String[1];
                    srcFilePaths[0] = Environment.getExternalStorageDirectory() + "/why";
                    String zipPath = Environment.getExternalStorageDirectory() + "/why.zip";
                    AntZipUtils.makeZip(srcFilePaths,zipPath);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return data;
        }
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if(isCancelled()){
                return;
            }
            try {
                Log.w("MainActivity","result="+result);
            }catch (Exception e) {
                if(! isCancelled()){
                    //showShortToast("文件壓縮失敗");
                    tv_show.setText("文件壓縮失敗");
                }
            } finally {
                if(! isCancelled()){
                    //隱藏對話框
                    //dismissProgressDialog();
                    tv_show.setText("壓縮完成");
                }
            }
        }
    }

    /**
     * 解壓文件的異步請求任務
     *
     */
    public class UnZipTask extends AsyncTask<String, Void, String>{

        @Override
        protected void onPreExecute() {
            //顯示進度對話框
            //showProgressDialog("");
            tv_show.setText("正在解壓...");
        }

        @Override
        protected String doInBackground(String... params) {
            String data = "";
            if(! isCancelled()){
                try {
                    String zipPath = Environment.getExternalStorageDirectory() + "/why.zip";
                    String targetDirPath = Environment.getExternalStorageDirectory() + "/why";
                    AntZipUtils.unZip(zipPath,targetDirPath);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return data;
        }
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if(isCancelled()){
                return;
            }
            try {
                Log.w("MainActivity","result="+result);
            }catch (Exception e) {
                if(! isCancelled()){
                    //showShortToast("文件解壓失敗");
                    tv_show.setText("文件解壓失敗");
                }
            } finally {
                if(! isCancelled()){
                    //隱藏對話框
                    //dismissProgressDialog();
                    tv_show.setText("解壓完成");
                }
            }
        }
    }
}

壓縮文件效果:

技術分享

解壓文件效果:

技術分享

混淆配置

#=====================基於Ant的Zip壓縮工具類 =====================
#android Studio環境中不需要,eclipse環境中需要
#-libraryjars libs/ant.jar
#不混淆第三方jar包中的類
-dontwarn org.apache.tools.**
-keep class org.apache.tools.**{*;}

參考資料

Zip壓縮工具類(基於JDK和基於ant.jar)

Android 解壓zip文件(支持中文)

【文件壓縮】 Android Jar、Zip文件壓縮和解壓縮處理

Android實現zip文件壓縮及解壓縮的方法

項目demo下載地址

https://github.com/haiyuKing/AntZipUtilsDemo

AntZipUtils【基於Ant的Zip壓縮解壓縮工具類】