zip4j 介绍和使用案例代码分享
原创
zip4j
最近在做文件分析需求的时候,有一个客户提供的 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 特征:
- 从 zip 文件创建,添加,提取,更新,删除文件
- 读/写密码保护的 zip 文件
- 支持 AES 128/256 加密
- 支持标准邮编加密
- 支持 zip64 格式
- 支持存储(无压缩)和 Deflate 压缩方法
- 从 split zip 文件创建或提取文件(例如:z01,z02,... zip)
- 支持 Unicode 文件名
- 进度监视器
实例
这里只提供几个 zip4j 的例子。
pom文件添加
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
压缩文件
- 压缩方式
- COMP_STORE = 0;(仅打包,不压缩)
- COMP_DEFLATE = 8;(默认)
- COMP_AES_ENC = 99; 加密压缩
- 压缩级别
- 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);
}
}
}
}
更多的例子,可以参考官网的例子和 API。