Java压缩和解压缩(二)Zip4j实践

Java压缩和解压缩
placeholder image
admin 发布于:2023-03-05 00:28:26
阅读:loading

1.基本介绍

Zip4j-用于zip文件/流的Java库,作用于zip文件或流的最全面的Java库,它还支持zip加密和解密,使得处理zip文件/流的代码实现更加容易,甚至可以是一行代码【项目作者非常谦虚的认为没有冒犯到Java的内置zip实现】,这个库的主要目标是为所有人提供一个简单的API zip文件或流,常见操作是在库中执行繁重的操作,而不需要开发人员担心除了可用性之外,这个库的另一个重要目标是为尽可能多的zip功能,有以下几个特征(翻译于Github上的项目主页https://github.com/srikanth-lingala/zip4j):

(1)创建、添加、提取、更新、从zip文件中删除文件;

(2)支持流(ZipInputStream和ZipOutputStreat);

(3)读/写受密码保护的zip文件和流;

(4)支持AES和zip标准加密方法;

(5)支持Zip64格式;

(6)储存(无压缩)和放气压缩方法;

(7)从分割的zip文件(例如:z01、z02、…zip)创建或提取文件;

(8)支持压缩文件中的Unicode文件名和注释;

(9)进度监视器-用于集成到应用程序和面向用户的应用程序;

所以,它被评为用于zip文件的最佳Java库,甚至被誉为地表最强的Java操作zip库。

2.代码实现

package cn.chendd.compress;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.UnzipParameters;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * zip4j组件的压缩和解压缩
 *
 * @author chendd
 * @date 2023/3/5 8:08
 */
public class CompressZip {

    /**
     * 压缩zip文件
     * @param outZipFile 源文件(夹)
     * @param file 输出zip文件
     * @param charset 字符编码
     * @param password 密码
     * @param comment 备注
     */
    public static void zip(File file, File outZipFile, Charset charset, String password, String comment) {
        if (outZipFile == null || file == null) {
            return;
        }
        ZipParameters parameter = new ZipParameters();
        //压缩方式,使用JDK内置zip
        parameter.setCompressionMethod(CompressionMethod.DEFLATE);
        ZipFile zipFile = new ZipFile(outZipFile);
        //如果编码不为空,则设置编码
        if (charset != null) {
            zipFile.setCharset(charset);
        }
        //如果密码不为空,则设置密码
        if (StringUtils.isNotEmpty(password)) {
            //压缩方式为标准压缩
            parameter.setEncryptionMethod(EncryptionMethod.ZIP_STANDARD);
            parameter.setEncryptFiles(true);
            zipFile.setPassword(password.toCharArray());
        }
        if (!file.exists()) {
            return;
        }
        try {
            //根据文件或文件夹进行压缩
            if (file.isFile()) {
                zipFile.addFile(file, parameter);
            } else if (file.isDirectory()) {
                zipFile.addFolder(file, parameter);
            }
            //设置注释
            if (StringUtils.isNotEmpty(comment)) {
                zipFile.setComment(comment);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 压缩zip文件
     * @param file 源文件(夹)
     * @param outZipFile 输出zip文件
     */
    public static void zip(File file, File outZipFile) {
        zip(file, outZipFile, Charset.forName("GBK"), null, null);
    }

    /**
     * 解压缩zip文件
     * @param inZipFile 压缩文件
     * @param file 文件
     * @param charset 编码
     * @param password 密码
     */
    public static void unzip(File inZipFile, File file, Charset charset, String password) {
        if (inZipFile == null || file == null) {
            throw new NullPointerException("文件不能为空");
        }
        try {
            if (!inZipFile.exists()) {
                throw new FileNotFoundException(inZipFile.getAbsolutePath());
            }
            ZipFile zipFile = new ZipFile(inZipFile);
            if (charset != null) {
                zipFile.setCharset(charset);
            }
            if (!zipFile.isValidZipFile()) {
                throw new IllegalArgumentException("zip文件格式不正确");
            }
            if (zipFile.isEncrypted()) {
                if (StringUtils.isEmpty(password)) {
                    throw new NullPointerException("解压密码不能为空");
                }
                zipFile.setPassword(password.toCharArray());
            }
            UnzipParameters parameter = new UnzipParameters();
            zipFile.extractAll(file.getAbsolutePath() , parameter);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解压缩文件
     * @param zipFile 压缩包文件
     * @param file 文件
     */
    public static void unzip(File zipFile , File file) {
        unzip(zipFile , file, Charset.forName("GBK"), null);
    }

    /**
     * 预览压缩包文件
     * @param zipFile 压缩包文件
     * @param charset 编码
     * @return 文件列表(不含子层文件夹(夹))
     */
    public static List<View> view(File zipFile, Charset charset) {
        ZipFile outZipFile = new ZipFile(zipFile);
        if (charset != null) {
            outZipFile.setCharset(charset);
        }
        List<FileHeader> fileHeaders;
        try {
            fileHeaders = outZipFile.getFileHeaders();
            List<View> resultList = new ArrayList<>();
            for (FileHeader header : fileHeaders) {
                View item = new View();
                item.setFileName(header.getFileName());
                item.setCompressedSize(header.getCompressedSize());
                item.setUncompressedSize(header.getUncompressedSize());
                item.setDirectory(header.isDirectory());
                item.setLastModifiedTime(header.getLastModifiedTime());
                resultList.add(item);
            }
            return resultList;
        } catch (ZipException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 预览压缩包文件
     * @param zipFile 压缩包文件
     * @return 文件列表(不含子层文件夹(夹))
     */
    public static List<View> view(File zipFile) {
        return view(zipFile, Charset.forName("GBK"));
    }

}
package cn.chendd.compress;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * 预览文件对象
 *
 * @author chendd
 * @date 2023/3/5 8:19
 */
@Data
public class View {

    /**
     * 文件名称
     */
    private String fileName;

    /**
     * 压缩前大小
     */
    private long compressedSize;

    /**
     * 压缩后大小
     */
    private long uncompressedSize;

    /**
     * 是否为文件夹
     */
    private boolean directory;

    /**
     * 最后修改时间
     */
    private long lastModifiedTime;

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }
}

3.测试代码

package cn.chendd.compress;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.MethodSorters;

import java.io.File;
import java.nio.charset.Charset;
import java.util.List;

/**
 * zip4j组件的压缩和解压缩测试
 *
 * @author chendd
 * @date 2023/3/5 8:38
 */
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class CompressZipTest {

    /**
     * 测试压缩文件
     */
    @Test
    public void toZipA() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File file = new File(projectHome , "源文件/哈喽.txt");
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_哈喽.zip");
        CompressZip.zip(file , zipFile);
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 测试压缩文件夹
     */
    @Test
    public void toZipB() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File file = new File(projectHome , "源文件/简单文件夹");
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_简单文件夹.zip");
        CompressZip.zip(file , zipFile);
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 测试多参数的压缩
     */
    @Test
    public void toZipC() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File file = new File(projectHome , "源文件/简单文件夹");
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_多参数_简单文件夹.zip");
        CompressZip.zip(file , zipFile , Charset.forName("GBK") , "https://www.chendd.cn" , "密码为:https://www.chendd.cn");
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 解压缩文件
     */
    @Test
    public void unZipA() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_哈喽.zip");
        File file = new File(projectHome , "解压缩文件夹/zip4j_哈喽");
        CompressZip.unzip(zipFile , file);
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 解压缩文件夹
     */
    @Test
    public void unZipB() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_简单文件夹.zip");
        File file = new File(projectHome , "解压缩文件夹/zip4j_简单文件夹");
        CompressZip.unzip(zipFile , file);
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    /**
     * 解压缩文件夹,包含多个参数
     */
    @Test
    public void unZipC() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_多参数_简单文件夹.zip");
        File file = new File(projectHome , "解压缩文件夹/zip4j_多参数_简单文件夹");
        CompressZip.unzip(zipFile , file , Charset.forName("GBK") , "https://www.chendd.cn");
        System.out.println("压缩源文件:" + file.getAbsolutePath());
        System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
    }

    @Test
    public void view() {
        File projectHome = new File(System.getProperty("user.dir")).getParentFile();
        File zipFile = new File(projectHome , "压缩文件夹/zip4j_多参数_简单文件夹.zip");
        System.out.println("预览压缩包的文件:");
        List<View> list = CompressZip.view(zipFile);
        list.forEach(System.out::println);
    }

}

4.运行示例

image.png

(压缩/解压缩文件结构)

image.png

(带密码压缩文件和备注)

5.实现说明

(1)本文使用开源项目zip4j实现的zip文件(夹)的压缩和解压缩,代码实现比前篇的基于JDK内置的API更加便捷和强大;

(2)本文示例包含文件压缩、文件解压缩、文件夹压缩、文件夹解压缩、压缩包文件列表预览;

(4)支持压缩文件的“注释说明”,支持压缩文件(夹)包含中文名称,支持压缩文件的密码压缩和解压缩;

(5)以上代码为示例代码,切勿直接使用:组件版本升级后ZipFile等对象需要close,所以上述的代码应该使用try-with-resource的写法来关闭IO;

(6)项目源码下载:源码下载.txt


 点赞


 发表评论

当前回复:作者

 评论列表


留言区