Zip文件是我們經常用到壓縮文件格式,android中在進行網絡請求大批量數據時,通常會採用傳遞zip文件,這樣做即可以減少網絡流量的消耗,加快請求的響應速度,又可以減少對存儲空間的要求,所以當我們將zip文件讀取回來的時候,如何解壓就是一個要解決的問題,雖然java本身提供了zip相關的API,但不是很強大,所以我們採用apache開源組織的zip4j,通過這個jar包可以十分輕鬆的解壓zip文件.
回到項目中去,項目中有個需求是從服務器請求雜誌,請求回來後給讀者展示,但是由於公司自己做的電子雜誌太大,最少也得20M,這是一個十分龐大的數據,所以與服務器商定採用zip來傳輸,可以降低文件的大小,減少服務器的壓力.我當時的處理過程:
1.使用HttpURLConnection與服務器取得連接,得到輸入流inputstream.
2.利用java zip流,將 inputstream轉化爲zip流.
3.記錄每次傳輸的位置,保存於臨時文件中.(用於斷點續傳,由於數據量大,所以要做斷點續傳,以後詳解)
4.循環讀取流完畢後生成一個zip文件,將zip文件解壓並實時將解壓進度顯示.
通過以上四步就完成了從服務器讀取zip包,並將zip包解壓給用戶展示,本文主要總結最後一步:
通過閱讀zip4j官網demo,可以得知,這個jar包本身是支持對解壓進度的讀取這一功能的.下面是我自己寫的一個demo,可以實時的將解壓進度發送出來,在界面上進行更新.
先看一下demo的解壓進度效果圖,比較簡單,有了數據後,效果想做的多複雜都可以,例如可以根據進度去繪製一個進度條等.
這是某一時刻的截圖.
代碼:
package util;
import java.io.File;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.progress.ProgressMonitor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
/**
* @author rzq
* @function 封裝一個解壓工具類,以後如果需要壓縮相關的方法,都放到此類中
*/
public class ZipUtil
{
private static final String password = "test123";
public static void unZipFileWithProgress(final File zipFile, final String filePath, final Handler handler,
final boolean isDeleteZip) throws ZipException
{
ZipFile zFile = new ZipFile(zipFile);
zFile.setFileNameCharset("GBK");
if (!zFile.isValidZipFile())
{ //
throw new ZipException("exception!");
}
File destDir = new File(filePath); // ��ѹĿ¼
if (destDir.isDirectory() && !destDir.exists())
{
destDir.mkdir();
}
if (zFile.isEncrypted())
{
zFile.setPassword(password); // 設置解壓密碼
}
final ProgressMonitor progressMonitor = zFile.getProgressMonitor();
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
Bundle bundle = null;
Message msg = null;
try
{
int precentDone = 0;
if (handler == null)
{
return;
}
handler.sendEmptyMessage(CompressStatus.START);
while (true)
{
// 每隔50ms,發送一個解壓進度出去
Thread.sleep(50);
precentDone = progressMonitor.getPercentDone();
bundle = new Bundle();
bundle.putInt(CompressStatus.PERCENT, precentDone);
msg = new Message();
msg.what = CompressStatus.HANDLING;
msg.setData(bundle);
handler.sendMessage(msg); //通過 Handler將進度扔出去
if (precentDone >= 100)
{
break;
}
}
handler.sendEmptyMessage(CompressStatus.COMPLETED);
}
catch (InterruptedException e)
{
bundle = new Bundle();
bundle.putString(CompressStatus.ERROR_COM, e.getMessage());
msg = new Message();
msg.what = CompressStatus.ERROR;
msg.setData(bundle);
handler.sendMessage(msg);
e.printStackTrace();
}
finally
{
if (isDeleteZip)
{
zipFile.delete();//將原壓縮文件刪除
}
}
}
});
thread.start();
zFile.setRunInThread(true); //true 在子線程中進行解壓 , false主線程中解壓
zFile.extractAll(filePath); //將壓縮文件解壓到filePath中...
}
}
/**
* 封裝不同的解壓狀態
*
**/
public class CompressStatus
{
public final static int START = 10000;
public final static int HANDLING = 10001;
public final static int COMPLETED = 10002;
public final static int ERROR = 10003;
public final static String PERCENT = "PERCENT";
public final static String ERROR_COM = "ERROR";
}
package com.example.zipprogress;
import java.io.File;
import net.lingala.zip4j.exception.ZipException;
import util.CompressStatus;
import util.ZipUtil;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
/**
* @author rzq
* @function 要更新的 UI
*/
public class MainActivity extends Activity {
TextView tv;
String zipFilePath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.text_progress);
zipFilePath = Environment.getExternalStorageDirectory().toString()
+ "/Desktop.zip";
File zipFile = new File(zipFilePath);
try {
ZipUtil.unZipFileWithProgress(zipFile,
Environment.getExternalStorageDirectory() + "/myTest/",
handler, false);
} catch (ZipException e) {
e.printStackTrace();
}
}
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case CompressStatus.START:
tv.setText("start!");
break;
case CompressStatus.HANDLING:
Bundle b = msg.getData();
tv.setText(b.getInt(CompressStatus.PERCENT) + "%");
break;
case CompressStatus.COMPLETED:
tv.setText("end!");
break;
case CompressStatus.ERROR:
tv.setText("error");
break;
}
};
};
}
總結: 主要就是對API的掌握和通過Handler對消息的傳遞,由於zip4j的下載需要翻強,所以我將demo代碼和zip4j包的源碼和jar文件都上傳,有需要的可以直接下載.