Java之批量分卷压缩与解压缩实现

  • 前言
  • 什么是分卷压缩
  • 分卷压缩如何压缩
  • 分卷压缩如何解压
  • Zip4j实现分卷压缩与解压
  • 环境配置
  • 实现代码
  • 存在问题
  • 参考链接


前言

什么是分卷压缩

  • 介绍
    分卷压缩是拆分压缩文件的一部分,通常分卷压缩是在将大型的压缩文件保存到数个磁盘或是可移动磁盘时使用。大部分主流压缩都支持分卷压缩了,常见的格式有:7z、ace、alz、bz2、gz、mou、rar、zip、zipx等。

分卷压缩如何压缩

  • 操作步骤(Windos)
  1. 首先电脑上要安装压缩软件,如WinRAR、好压等等
  2. 准备好需要分卷压缩的文件,点击将要分卷压缩的文件,然后点击鼠标右键选择"添加到压缩文件",进行文件压缩
  3. 选择自定义,在"压缩分卷大小"中选择一个合适的大小,比如2M等,然后还可以选择压缩所使用的格式
  4. 点击"立即压缩"开始分卷压缩

分卷压缩如何解压

  • 操作步骤(Windos)
  1. 保证分卷压缩文件数量完整
  2. 将所有的压缩分卷文件放在同一个文件夹中
  3. 任意选择一个压缩文件,点击鼠标右键,选择解压到当前文件

Zip4j实现分卷压缩与解压

环境配置

  • 官网地址
    http://www.lingala.net/zip4j.html
  • 引入依赖
<!-- zip4j依赖 -->
    <dependency>
        <groupId>net.lingala.zip4j</groupId>
        <artifactId>zip4j</artifactId>
        <version>1.3.2</version>
    </dependency>

    <!-- commons-lang3依赖 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.7</version>
    </dependency>

实现代码

  • 分卷压缩
/**
    *
    * @param srcFiles 要压缩的文件绝对路径列表(支持多个文件的合并压缩)
    * @param destFile 要压缩的zip文件名
    * @param passwd   压缩密码
    * @param fileSize 分卷大小
    * @return    压缩文件路径(如分卷会返回以 "," 分隔的文件路径列表)
    */
    public static String zipBySplit(List<String> srcFiles, String destFile, String passwd, long fileSize) throws ZipException {

        String zipFiles = null;
        File tmpFile = new File(destFile);
        if (tmpFile.exists()) {
            tmpFile.delete();
        }
        //创建压缩文件对象
        ZipFile zipFile = new ZipFile(destFile);
        //创建文档对象集合
        ArrayList<File> filesToAdd = new ArrayList<File>();
        //判断源压缩文件列表是否为空
        if (null != srcFiles && srcFiles.size()>0) {
            int fileCount = srcFiles.size();
            for (int i = 0; i < fileCount; i++) {
                filesToAdd.add(new File(srcFiles.get(i)));
            }

            //设置压缩参数
            ZipParameters parameters = new ZipParameters();
            //设置压缩密码
            if (!StringUtils.isBlank(passwd)) {
                parameters.setEncryptFiles(true);
                parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
                parameters.setPassword(passwd.toCharArray());
            }
            //设置压缩方式-默认
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            //设置压缩级别-一般
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
            //设置默认分割大小为64KB
            //SplitLenth has to be greater than 65536 bytes
            if (fileSize == 0) {
                fileSize = 65536;
            }
            //创建分卷压缩文件
            zipFile.createZipFile(filesToAdd,parameters,true,fileSize);

            //获取分卷下载列表
            ArrayList<String> zipList = zipFile.getSplitZipFiles();
            if (null != zipList && zipList.size()>0) {
                String surFix = ".z010";
                String surFixReplace = ".z10";
                //单独处理第10个包的文件名做特殊处理
                for (int i = 0; i < zipList.size(); i++) {
                    String file = zipList.get(i).trim();
                    int length = file.length();
                    String surFixTmp = file.substring(length - 5, length);
                    if (surFix.equals(surFixTmp)) {
                        file = file.replace(surFix, surFixReplace);
                    }
                    zipList.set(i,file);
                }

                //初始化压缩数组
                String[] zipArray = new String[zipList.size()];
                zipList.toArray(zipArray);
                zipFiles = Arrays.toString(zipArray);
                int length = zipFiles.length();
                zipFiles = zipFiles.substring(1,length-1);
            }

        }
        return zipFiles;
    }
  • 解压ZIP压缩文件到指定目录
/**
    *  解压缩(支持分卷压缩解压)
    * @param zipFilePath   指定的ZIP压缩文件 路径
    * @param dest          解压目录
    * @param passwd        ZIP文件的密码 。需要解压密码时必须传入,否则传入null即可
    * @return              解压后文件名数组
    * @throws ZipException 压缩文件有损坏或者解压缩失败抛出
    */
    public static String[] unzipBySplit(String zipFilePath,String dest,String passwd) throws ZipException {

        File zipFile = new File(zipFilePath);
        ZipFile zFile = new ZipFile(zipFile);
        //设置编码格式
        zFile.setFileNameCharset("GBK");
        if (!zFile.isValidZipFile()) {
            throw new ZipException("压缩文件不合法,可能被损坏!");
        }
        File destDir = new File(dest);
        //判断是文件夹路径且不存在
        if (destDir.isDirectory() && !destDir.exists()) {
            destDir.mkdir();
        }
        //判断文件是否加密
        if (zFile.isEncrypted()) {
            if (StringUtils.isBlank(passwd)) {
                throw new ZipException("文件已加密,需要解压密码,解压密码不能为空!");
            } else {
                zFile.setPassword(passwd.toCharArray());
            }

        }
        //解压文件
        zFile.extractAll(dest);
        ArrayList<String> extractedFileList = new ArrayList<String>();
        List<FileHeader> headerList = zFile.getFileHeaders();
        if (headerList != null && headerList.size()>0) {
            for (FileHeader fileHeader : headerList) {
                if (!fileHeader.isDirectory()) {
                    extractedFileList.add(fileHeader.getFileName());
                }
            }
        }

        String[] extractedFiles = new String[extractedFileList.size()];
        extractedFileList.toArray(extractedFiles);
        return extractedFiles;
    }
  • 测试入口
public static void main(String[] args) {

        //带压缩文件集合
        ArrayList<String> srcFiles = new ArrayList<String>();
        srcFiles.add("D:/Git/Git&GitHub.pdf");


        String destFile = "D:/Git/zipTest/Git.zip"; //压缩路径

        String passwd  = "123"; //压缩包密码
        long fileSize = 65536; //分卷大小(当前为最小值)

        try {
            //1.压缩
            System.out.println(zipBySplit(srcFiles,destFile,passwd,fileSize));

            //2.解压
            String[] extractedFiles=unzipBySplit(destFile, "D:/Git/zipTest/unzip", passwd);
            for (int i = 0; i < extractedFiles.length; i++) {
                System.out.println(extractedFiles[i]);
            }

        } catch (ZipException e) {
            e.printStackTrace();
        }
    }

存在问题

  • 压缩
  1. 第二次压缩的时候,代码中只删除了指定目标压缩文件,其他分卷压缩的文件无法再次创建
  • 解压
  1. 为什么只能解压指定创建的目标压缩文件(Git.zip)才能成功解压,解压其他分卷压缩的文件文件失败,报错文件可能已损坏
  2. 压缩的时候创建的指定目标压缩文件是属于分卷压缩文件的一部分还是说单独是一个压缩文件,跟Windows系统下分卷压缩文件显示的压缩后列表存在差异化,另外Windows下分卷压缩是从001开始,无单独的类似文件名称进行压缩(如Git.zip),而是直接从Git.zip.001开始

参考

  • zip4j – Java处理zip压缩文件的完整解决方案
  • ZIP4j 压缩与解压
  • 使用Zip4j分卷压缩和解压缩
  • create multipart compressed zip file in java