AntZipUtils【基于Ant的Zip压缩解压缩工具类】
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
- 基于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(); } }
在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.**{*;}
参考资料
【文件压缩】 Android Jar、Zip文件压缩和解压缩处理