閒言少敘,先說ZIP壓縮。
zip壓縮需要通過ZipOutputStream 執行write方法將壓縮數據寫到指定輸出流中。
注意,這裏應先使用CheckedOutputStream 指定文件校驗算法。(通常使用CRC32算法)。代碼如下所示:
- CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(destPath), new CRC32());
- ZipOutputStream zos = new ZipOutputStream(cos);
接下來,需要將待壓縮文件以ZipEntry的方式追加到壓縮文件中,如下所示:
- /**
- * 壓縮包內文件名定義
- *
- * <pre>
- * 如果有多級目錄,那麼這裏就需要給出包含目錄的文件名
- * 如果用WinRAR打開壓縮包,中文名將顯示爲亂碼
- * </pre>
- */
- ZipEntry entry = new ZipEntry(dir + file.getName());
- zos.putNextEntry(entry);
ZipEntry就是壓縮包中的每一個實體!
完成上述準備後,就可以執行壓縮操作了。實際上,就是執行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();
當然,如果待添加的壓縮項是一個目錄。那麼,需要通過遞歸的方式指定最終的壓縮項。
如果要添加一個空目錄,注意使用符號"/"(String PATH="/";)作爲添加項名字結尾符!
遞歸構建目錄壓縮,代碼如下:
- /**
- * 壓縮
- *
- * @param srcFile
- * 源路徑
- * @param zos
- * ZipOutputStream
- * @param basePath
- * 壓縮包內相對路徑
- * @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();
- // 構建空目錄
- 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是一個空目錄,用WinRAR打開後,可以看到這個目錄下還有一個空文件名文件!
來個完整的壓縮實現,代碼如下所示:
- /**
- * 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:[email protected]">樑棟</a>
- * @since 1.0
- */
- public class ZipUtils {
- public static final String EXT = ".zip";
- private static final String BASE_DIR = "";
- // 符號"/"用來作爲目錄標識判斷符
- 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
- * 目標路徑
- * @throws Exception
- */
- public static void compress(File srcFile, File destFile) throws Exception {
- // 對輸出文件做CRC32校驗
- 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
- * 壓縮包內相對路徑
- * @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
- * 目標文件路徑
- *
- */
- 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();
- // 構建空目錄
- 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
- * 壓縮文件中的當前路徑
- * @throws Exception
- */
- private static void compressFile(File file, ZipOutputStream zos, String dir)
- throws Exception {
- /**
- * 壓縮包內文件名定義
- *
- * <pre>
- * 如果有多級目錄,那麼這裏就需要給出包含目錄的文件名
- * 如果用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();
- }
- }
來做個簡單的測試:
- 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");
- }
- }
現在用WinRAR打開看看,是不是效果幾乎一致?
當然,上述代碼有所不足之處主要是中文名稱亂碼問題。用java原生ZIP實現壓縮後得到的壓縮包,與系統的字符集不同,文件/目錄名將出現亂碼。這是所有歸檔壓縮都會遇到的問題。對於這種問題,Commons Copress提供瞭解決方案!
對於解壓縮,請關注後續內容!