去年整理了一篇ZLib算法Java實(shí)現(xiàn)(
Java壓縮技術(shù)(一) ZLib),一直惦記卻沒時(shí)間補(bǔ)充。今天得空,整理一下ZIP的java原生實(shí)現(xiàn)。
看了幾篇zip壓縮算法的帖子,講的算是比較細(xì)致了,但就是沒有對(duì)應(yīng)的解壓縮實(shí)現(xiàn),太惜敗了!
我就喜歡沒事做總結(jié),稍作整理,將其收納!
相關(guān)鏈接:
Java壓縮技術(shù)(一) ZLib Java壓縮技術(shù)(二) ZIP壓縮——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(三) ZIP解壓縮——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(四) GZIP——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(五) GZIP相關(guān)——瀏覽器解析 Java壓縮技術(shù)(六) BZIP2——Commons實(shí)現(xiàn) Java壓縮技術(shù)(七) TAR——Commons實(shí)現(xiàn) 查過相關(guān)資料后才知道,ZIP應(yīng)該算作歸檔類的壓縮算法,每一門學(xué)科都可深可淺!
閑言少敘,先說ZIP壓縮。
zip壓縮需要通過ZipOutputStream 執(zhí)行write方法將壓縮數(shù)據(jù)寫到指定輸出流中。
注意,這里應(yīng)先使用CheckedOutputStream 指定文件校驗(yàn)算法。(通常使用CRC32算法)。代碼如下所示:
- CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(destPath), new CRC32());
- ZipOutputStream zos = new ZipOutputStream(cos);
接下來,需要將待壓縮文件以ZipEntry的方式追加到壓縮文件中,如下所示:
- /**
- * 壓縮包內(nèi)文件名定義
- *
- * <pre>
- * 如果有多級(jí)目錄,那么這里就需要給出包含目錄的文件名
- * 如果用WinRAR打開壓縮包,中文名將顯示為亂碼
- * </pre>
- */
- ZipEntry entry = new ZipEntry(dir file.getName());
-
- zos.putNextEntry(entry);
ZipEntry就是壓縮包中的每一個(gè)實(shí)體!
完成上述準(zhǔn)備后,就可以執(zhí)行壓縮操作了。實(shí)際上,就是執(zhí)行ZipOutputStream類的write方法,如下所示:
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
-
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- zos.write(data, 0, count);
- }
- bis.close();
當(dāng)然,如果待添加的壓縮項(xiàng)是一個(gè)目錄。那么,需要通過遞歸的方式指定最終的壓縮項(xiàng)。
如果要添加一個(gè)空目錄,注意使用符號(hào)"/"(String PATH="/";)作為添加項(xiàng)名字結(jié)尾符! 遞歸構(gòu)建目錄壓縮,代碼如下:
- /**
- * 壓縮
- *
- * @param srcFile
- * 源路徑
- * @param zos
- * ZipOutputStream
- * @param basePath
- * 壓縮包內(nèi)相對(duì)路徑
- * @throws Exception
- */
- private static void compress(File srcFile, ZipOutputStream zos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- compressDir(srcFile, zos, basePath);
- } else {
- compressFile(srcFile, zos, basePath);
- }
- }
-
- /**
- * 壓縮目錄
- *
- * @param dir
- * @param zos
- * @param basePath
- * @throws Exception
- */
- private static void compressDir(File dir, ZipOutputStream zos,
- String basePath) throws Exception {
-
- File[] files = dir.listFiles();
-
- // 構(gòu)建空目錄
- if (files.length < 1) {
- ZipEntry entry = new ZipEntry(basePath dir.getName() PATH);
-
- zos.putNextEntry(entry);
- zos.closeEntry();
- }
-
- for (File file : files) {
- // 遞歸壓縮
- compress(file, zos, basePath dir.getName() PATH);
- }
- }
x是一個(gè)空目錄,用WinRAR打開后,可以看到這個(gè)目錄下還有一個(gè)空文件名文件!
來個(gè)完整的壓縮實(shí)現(xiàn),代碼如下所示:
- /**
- * 2010-4-12
- */
- package org.zlex.commons.io;
-
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.util.zip.CRC32;
- import java.util.zip.CheckedInputStream;
- import java.util.zip.CheckedOutputStream;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipInputStream;
- import java.util.zip.ZipOutputStream;
-
- /**
- * ZIP壓縮工具
- *
- * @author <a href="mailto:zlex.dongliang@gmail.com">梁棟</a>
- * @since 1.0
- */
- public class ZipUtils {
-
- public static final String EXT = ".zip";
- private static final String BASE_DIR = "";
-
- // 符號(hào)"/"用來作為目錄標(biāo)識(shí)判斷符
- private static final String PATH = "/";
- private static final int BUFFER = 1024;
-
- /**
- * 壓縮
- *
- * @param srcFile
- * @throws Exception
- */
- public static void compress(File srcFile) throws Exception {
- String name = srcFile.getName();
- String basePath = srcFile.getParent();
- String destPath = basePath name EXT;
- compress(srcFile, destPath);
- }
-
- /**
- * 壓縮
- *
- * @param srcFile
- * 源路徑
- * @param destPath
- * 目標(biāo)路徑
- * @throws Exception
- */
- public static void compress(File srcFile, File destFile) throws Exception {
-
- // 對(duì)輸出文件做CRC32校驗(yàn)
- CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(
- destFile), new CRC32());
-
- ZipOutputStream zos = new ZipOutputStream(cos);
-
- compress(srcFile, zos, BASE_DIR);
-
- zos.flush();
- zos.close();
- }
-
- /**
- * 壓縮文件
- *
- * @param srcFile
- * @param destPath
- * @throws Exception
- */
- public static void compress(File srcFile, String destPath) throws Exception {
- compress(srcFile, new File(destPath));
- }
-
- /**
- * 壓縮
- *
- * @param srcFile
- * 源路徑
- * @param zos
- * ZipOutputStream
- * @param basePath
- * 壓縮包內(nèi)相對(duì)路徑
- * @throws Exception
- */
- private static void compress(File srcFile, ZipOutputStream zos,
- String basePath) throws Exception {
- if (srcFile.isDirectory()) {
- compressDir(srcFile, zos, basePath);
- } else {
- compressFile(srcFile, zos, basePath);
- }
- }
-
- /**
- * 壓縮
- *
- * @param srcPath
- * @throws Exception
- */
- public static void compress(String srcPath) throws Exception {
- File srcFile = new File(srcPath);
-
- compress(srcFile);
- }
-
- /**
- * 文件壓縮
- *
- * @param srcPath
- * 源文件路徑
- * @param destPath
- * 目標(biāo)文件路徑
- *
- */
- public static void compress(String srcPath, String destPath)
- throws Exception {
- File srcFile = new File(srcPath);
-
- compress(srcFile, destPath);
- }
-
- /**
- * 壓縮目錄
- *
- * @param dir
- * @param zos
- * @param basePath
- * @throws Exception
- */
- private static void compressDir(File dir, ZipOutputStream zos,
- String basePath) throws Exception {
-
- File[] files = dir.listFiles();
-
- // 構(gòu)建空目錄
- if (files.length < 1) {
- ZipEntry entry = new ZipEntry(basePath dir.getName() PATH);
-
- zos.putNextEntry(entry);
- zos.closeEntry();
- }
-
- for (File file : files) {
-
- // 遞歸壓縮
- compress(file, zos, basePath dir.getName() PATH);
-
- }
- }
-
- /**
- * 文件壓縮
- *
- * @param file
- * 待壓縮文件
- * @param zos
- * ZipOutputStream
- * @param dir
- * 壓縮文件中的當(dāng)前路徑
- * @throws Exception
- */
- private static void compressFile(File file, ZipOutputStream zos, String dir)
- throws Exception {
-
- /**
- * 壓縮包內(nèi)文件名定義
- *
- * <pre>
- * 如果有多級(jí)目錄,那么這里就需要給出包含目錄的文件名
- * 如果用WinRAR打開壓縮包,中文名將顯示為亂碼
- * </pre>
- */
- ZipEntry entry = new ZipEntry(dir file.getName());
-
- zos.putNextEntry(entry);
-
- BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
- file));
-
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = bis.read(data, 0, BUFFER)) != -1) {
- zos.write(data, 0, count);
- }
- bis.close();
-
- zos.closeEntry();
- }
-
- }
來做個(gè)簡(jiǎn)單的測(cè)試:
- import static org.junit.Assert.*;
-
- import org.junit.Test;
-
- /**
- *
- * @author 梁棟
- * @version 1.0
- * @since 1.0
- */
- public class ZipUtilsTest {
-
- /**
- *
- */
- @Test
- public void test() throws Exception {
- // 壓縮文件
- ZipUtils.compress("d:\\f.txt");
- // 壓縮目錄
- ZipUtils.compress("d:\\fd");
- }
- }
現(xiàn)在用WinRAR打開看看,是不是效果幾乎一致?
當(dāng)然,上述代碼有所不足之處主要是中文名稱亂碼問題。用java原生ZIP實(shí)現(xiàn)壓縮后得到的壓縮包,與系統(tǒng)的字符集不同,文件/目錄名將出現(xiàn)亂碼。這是所有歸檔壓縮都會(huì)遇到的問題。對(duì)于這種問題,Commons Copress提供了解決方案!
對(duì)于解壓縮,請(qǐng)關(guān)注后續(xù)內(nèi)容!
相關(guān)鏈接:
Java壓縮技術(shù)(一) ZLib Java壓縮技術(shù)(二) ZIP壓縮——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(三) ZIP解壓縮——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(四) GZIP——Java原生實(shí)現(xiàn) Java壓縮技術(shù)(五) GZIP相關(guān)——瀏覽器解析 Java壓縮技術(shù)(六) BZIP2——Commons實(shí)現(xiàn) Java壓縮技術(shù)(七) TAR——Commons實(shí)現(xiàn)
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。