复制本文链接

最近在做文件分析需求的时候,有一个客户提供的 zip 压缩包,不能正常解压,可能不是符合 zip 严格规范的文件,使用 java zip api 访问直接报错:

Exception in thread "main" java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
	at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:310)
	at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:122)
	at com.daimafans.compress.App.main(App.java:40)

使用 commons-compress 最终适配解决还是报错:

java.util.zip.ZipException: Unexpected record signature: 0X742E3436
	at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.getNextZipEntry(ZipArchiveInputStream.java:260)
	at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.getNextEntry(ZipArchiveInputStream.java:408)
	at com.daimafans.compress.App.getNextEntry(App.java:42)
	at com.daimafans.compress.App.main(App.java:25)

但是使用 7z 或者 linux unzip 都可以正常解压,无奈寻求其它方式。后来发现了 zip4j,zip4j 功能比较强大,支持加密、解密压缩,支持文件的添加、删除等,可以选择将文件只打包不压缩,然后可以特别灵活的添加、删除文件。

zip4j 介绍

zip4j 官网:http://www.lingala.net/zip4j/ 可以在 “download” 页面下载官方示例进行学习。

zip4j 特征:

  1. 从 zip 文件创建,添加,提取,更新,删除文件
  2. 读/写密码保护的 zip 文件
  3. 支持 AES 128/256 加密
  4. 支持标准邮编加密
  5. 支持 zip64 格式
  6. 支持存储(无压缩)和 Deflate 压缩方法
  7. 从 split zip 文件创建或提取文件(例如:z01,z02,… zip)
  8. 支持 Unicode 文件名
  9. 进度监视器

实例

这里只提供几个 zip4j 的例子。

pom文件添加

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>1.3.2</version>
</dependency>

压缩文件

  1. 压缩方式
  • COMP_STORE = 0;(仅打包,不压缩)
  • COMP_DEFLATE = 8;(默认)
  • COMP_AES_ENC = 99; 加密压缩
  1. 压缩级别
  • DEFLATE_LEVEL_FASTEST = 1; (速度最快,压缩比最小)
  • DEFLATE_LEVEL_FAST = 3; (速度快,压缩比小)
  • DEFLATE_LEVEL_NORMAL = 5; (一般)
  • DEFLATE_LEVEL_MAXIMUM = 7;
  • DEFLATE_LEVEL_ULTRA = 9;
package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.File;

/**
 * 压缩文件夹
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class ZipFiles
{
    public static void main(String[] args) throws ZipException
    {
        // 生成的压缩文件
        ZipFile zipFile = new ZipFile("D:\\test.zip");

        ZipParameters parameters = new ZipParameters();
        // 压缩方式
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        // 压缩级别
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);

        // 要打包的文件夹
        File currentFile = new File("D:\\test");
        File[] files = currentFile.listFiles();

        // 遍历test文件夹下所有的文件、文件夹
        assert files != null;
        for (File file : files)
        {
            if (file.isDirectory())
            {
                zipFile.addFolder(file.getPath(), parameters);
            }
            else
            {
                zipFile.addFile(file, parameters);
            }
        }
    }
}

解压文件

解压 API 也比较丰富,可以单独抽取内部文件,或者直接输出到目标解压文件夹,判断文件是否加密,加密压缩包在解压的时候可以添加压缩密码等。

package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;

/**
 * 解压到指定文件夹
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class UnZipFiles
{
    public static void main(String[] args)
    {
        try
        {
            ZipFile zipFile = new ZipFile("D:\\test.zip");

            // 如果解压需要密码
            if (zipFile.isEncrypted())
            {
                zipFile.setPassword("111");
            }

            zipFile.extractAll("D:\\test");
        }
        catch (ZipException e)
        {
            e.printStackTrace();
        }
    }
}

添加文件到压缩文件中

发现一个问题,这种方式添加文件时,只能添加一次,再次添加会失败,没有发现原因。

package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.File;
import java.util.ArrayList;

/**
 * 添加文件到压缩文件中
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class AddFileToZip
{
    public static void main(String[] args)
    {
        try
        {
            ZipFile zipFile = new ZipFile("D:\\test.zip");

            ArrayList<File> addFiles = new ArrayList<>();
            addFiles.add(new File("D:\\addFile1.txt"));
            addFiles.add(new File("D:\\addFile2.txt"));

            ZipParameters parameters = new ZipParameters();
            parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
            // 目标路径
            parameters.setRootFolderInZip("ks/");

            zipFile.addFiles(addFiles, parameters);

            // 可以添加单个文件
            // zipFile.addFile(new File("D:\\addFile2.txt"), parameters);//
        }
        catch (ZipException e)
        {
            e.printStackTrace();
        }
    }
}

以流的方式添加文件

这种方想比直接添加文件优势在于可以多次添加。

package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 流的方式添加文件
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class AddInputStreamToZip
{
    public static void main(String[] args)
    {
        InputStream is = null;
        try
        {
            ZipFile zip = new ZipFile("D:\\test.zip");

            ZipParameters para = new ZipParameters();
            para.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
            para.setFileNameInZip("ks/add.txt");
            para.setSourceExternalStream(true);

            is = new ByteArrayInputStream("这是文件内容".getBytes());
            zip.addStream(is, para);
        }
        catch (ZipException e)
        {
            e.printStackTrace();
        }
        finally
        {
            if (is != null)
            {
                try
                {
                    is.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

删除压缩文件中的文件

测试发现不能直接删除压缩文件中的文件夹。

package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;

/**
 * 删除压缩文件中的文件
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class DeleteFromZip
{
    public static void main(String[] args)
    {
        try
        {
            ZipFile zipFile = new ZipFile("D:\\test.zip");
            zipFile.removeFile("ks/add.txt");
        }
        catch (ZipException e)
        {
            e.printStackTrace();
        }
    }
}

创建带密码的压缩文件

可以在创建 zip 压缩包文件的时候添加密码。

package com.daimafans.demo;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.File;

/**
 * 创建带密码的压缩文件
 *
 * @author daimafans.com
 * @date 2018-11-29
 */
public class ZipFileWithPwd
{
    public static void main(String[] args) throws ZipException
    {
        // 生成的压缩文件
        ZipFile zipFile = new ZipFile("D:\\test.zip");

        ZipParameters parameters = new ZipParameters();
        // 压缩方式
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        // 压缩级别
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        parameters.setEncryptFiles(true);
        parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
        parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
        parameters.setPassword("111");

        // 要打包的文件夹
        File currentFile = new File("D:\\test");
        File[] files = currentFile.listFiles();

        // 遍历test文件夹下所有的文件、文件夹
        assert files != null;
        for (File file : files)
        {
            if (file.isDirectory())
            {
                zipFile.addFolder(file.getPath(), parameters);
            }
            else
            {
                zipFile.addFile(file, parameters);
            }
        }
    }
}

https://www.daimafans.com/codeshare/d13857959055458304-p1-o1.html

阿里云老用户专享阿里云双12 阿里云双12

发表评论

电子邮件地址不会被公开。 必填项已用*标注

78 − 71 =