zip文件的解压可以使用java的zip库,但是没有实现对加密文件的解压功能,这里可以使用zip4j来实现。具体可以参看该文《Android下zip压缩文件加密解密的完美解决方案》。该文件中没有实现解压进度的功能,这里进行一简单的实现。
Zip4jSp.java
/** * unzip file to dest dir with password in thread. * * @param zipFile * @param dest * @param passwd * @param charset * null or empty is utf-8 * @param Handler * handler in thread * @param isDeleteZipFile * true:delete zip file.false:not. * @throws ZipException */ public static void Unzip(final File zipFile, String dest, String passwd, String charset, final Handler handler, final boolean isDeleteZipFile) throws ZipException { ZipFile zFile = new ZipFile(zipFile); if (TextUtils.isEmpty(charset)) { charset = "UTF-8"; } zFile.setFileNameCharset(charset); if (!zFile.isValidZipFile()) { throw new ZipException( "Compressed files are not illegal, may be damaged."); } File destDir = new File(dest); // Unzip directory if (destDir.isDirectory() && !destDir.exists()) { destDir.mkdir(); } if (zFile.isEncrypted()) { zFile.setPassword(passwd.toCharArray()); } final ProgressMonitor progressMonitor = zFile.getProgressMonitor(); Thread progressThread = new Thread(new Runnable() { @Override public void run() { Bundle bundle = null; Message msg = null; try { int percentDone = 0; // long workCompleted=0; // handler.sendEmptyMessage(ProgressMonitor.RESULT_SUCCESS) if (handler == null) { return; } handler.sendEmptyMessage(CompressStatus.START); while (true) { Thread.sleep(1000); percentDone = progressMonitor.getPercentDone(); bundle = new Bundle(); bundle.putInt(CompressKeys.PERCENT, percentDone); msg = new Message(); msg.what = CompressStatus.HANDLING; msg.setData(bundle); handler.sendMessage(msg); if (percentDone >= 100) { break; } } handler.sendEmptyMessage(CompressStatus.COMPLETED); } catch (InterruptedException e) { bundle = new Bundle(); bundle.putString(CompressKeys.ERROR, e.getMessage()); msg = new Message(); msg.what = CompressStatus.ERROR; msg.setData(bundle); handler.sendMessage(msg); e.printStackTrace(); } finally { if(isDeleteZipFile) { zipFile.deleteOnExit();//zipFile.delete(); } } } }); progressThread.start(); zFile.setRunInThread(true); zFile.extractAll(dest); }
注:
(1)、字符集默认采用UTF-8
(2)、解压文件在线程中进行,所以需要setRunInThread(true).由于采用线程中解压文件,所以调用该函数时相当于异步执行,调用代码会直接往下走,需要注意并加以处理。
(3)、进度条另开了一个线程来处理,并将处理的结果以handler的形式发送
(4)、使用zipFile.deleteOnExit()而不是zipFile.delete();因为使用线程解压时,虽然从progressMonitor获得的percentDone已经达到了100,而事实上数据并没有完全解压完成。这时退出循环执行finally的delete函数,如果使用zipFile.delete(),将会删除文件,这样会使后续的解压失败。而使用zipFile.deleteOnExit()函数,该函数是当VM终止时才会删除文件,与zipFile.delete()删除文件不同。APP在运行时,VM始终是在的,所以这样删除可以确保后续的解压能够正常进行。或者不去删除文件。
(5)、handler的代码见后文的MainActivity.java。
package com.sparkle.compress; public class CompressKeys { public final static String PERCENT="PERCENT"; public final static String ERROR="ERROR"; }
CompressStatus.java
package com.sparkle.compress; public class CompressStatus { public final static int START=0; public final static int HANDLING=1; public final static int COMPLETED=2; public final static int ERROR=3; }
private Handler _handler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case CompressStatus.START: { setTitle("Start..."); break; } case CompressStatus.HANDLING: { Bundle bundle=msg.getData(); int percent=bundle.getInt(CompressKeys.PERCENT); setTitle(percent+"%"); break; } case CompressStatus.ERROR: { Bundle bundle=msg.getData(); String error=bundle.getString(CompressKeys.ERROR); _info_textView.setText(error); break; } case CompressStatus.COMPLETED: { setTitle("Completed"); byte[] data=FileSp.read(tempFilePath); try { String dataStr=new String(data,"UTF-8"); _info_textView.setText(dataStr); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; } default: break; } }; }; }
下面是效果图