提问人:pathikrit 提问时间:2/17/2012 最后编辑:pathikrit 更新时间:5/4/2023 访问量:260313
什么是好的 Java 库来压缩/解压缩文件?[已结束]
What is a good Java library to zip/unzip files? [closed]
问:
我们不允许向读者、工具、软件库等寻求推荐的问题。您可以编辑问题,以便用事实和引文来回答。
7年前关闭。
我查看了 JDK 和 Apache 压缩库附带的默认 Zip 库,我对它们不满意,原因有 3 个:
它们臃肿且 API 设计不佳。我必须编写 50 行样板字节数组输出、zip 输入、文件输出流并关闭相关流并捕获异常并自行移动字节缓冲区?为什么我不能有一个简单的 API 看起来像这样并且可以正常工作?
Zipper.unzip(InputStream zipFile, File targetDirectory, String password = null)
Zipper.zip(File targetDirectory, String password = null)
似乎压缩解压缩会破坏文件元数据并且密码处理已损坏。
另外,与我使用 UNIX 获得的命令行 zip 工具相比,我尝试的所有库都慢了 2-3 倍?
对我来说,(2)和(3)是次要的点,但我真的想要一个经过测试的库,有一个单行界面。
答:
你看过 http://commons.apache.org/vfs/ 吗?它声称可以为您简化很多事情。但我从来没有在项目中使用过它。
我也不知道 JDK 或 Apache 压缩以外的 Java 原生压缩库。
我记得有一次我们从 Apache Ant 中扯掉了一些功能——它们内置了很多用于压缩/解压缩的实用程序。
VFS 的示例代码如下所示:
File zipFile = ...;
File outputDir = ...;
FileSystemManager fsm = VFS.getManager();
URI zip = zipFile.toURI();
FileObject packFileObject = fsm.resolveFile(packLocation.toString());
FileObject to = fsm.toFileObject(destDir);
FileObject zipFS;
try {
zipFS = fsm.createFileSystem(packFileObject);
fsm.toFileObject(outputDir).copyFrom(zipFS, new AllFileSelector());
} finally {
zipFS.close();
}
评论
仅使用 JDK 提取 zip 文件及其所有子文件夹:
private void extractFolder(String zipFile,String extractFolder)
{
try
{
int BUFFER = 2048;
File file = new File(zipFile);
ZipFile zip = new ZipFile(file);
String newPath = extractFolder;
new File(newPath).mkdir();
Enumeration zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements())
{
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
//destFile = new File(newPath, destFile.getName());
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory())
{
BufferedInputStream is = new BufferedInputStream(zip
.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos,
BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
}
}
catch (Exception e)
{
Log("ERROR: "+e.getMessage());
}
}
Zip 文件及其所有子文件夹:
private void addFolderToZip(File folder, ZipOutputStream zip, String baseName) throws IOException {
File[] files = folder.listFiles();
for (File file : files) {
if (file.isDirectory()) {
addFolderToZip(file, zip, baseName);
} else {
String name = file.getAbsolutePath().substring(baseName.length());
ZipEntry zipEntry = new ZipEntry(name);
zip.putNextEntry(zipEntry);
IOUtils.copy(new FileInputStream(file), zip);
zip.closeEntry();
}
}
}
评论
一个非常好的项目是TrueZip。
TrueZIP 是一个基于 Java 的虚拟文件系统 (VFS) 插件框架,它提供对归档文件的透明访问,就好像它们只是普通目录一样
例如(来自网站):
File file = new TFile("archive.tar.gz/README.TXT");
OutputStream out = new TFileOutputStream(file);
try {
// Write archive entry contents here.
...
} finally {
out.close();
}
评论
在 Java 8 中,使用 Apache Commons-IO 的 IOUtils
可以做到这一点:
try (java.util.zip.ZipFile zipFile = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File entryDestination = new File(outputDir, entry.getName());
if (entry.isDirectory()) {
entryDestination.mkdirs();
} else {
entryDestination.getParentFile().mkdirs();
try (InputStream in = zipFile.getInputStream(entry);
OutputStream out = new FileOutputStream(entryDestination)) {
IOUtils.copy(in, out);
}
}
}
}
它仍然是一些样板代码,但它只有 1 个非外来依赖项:Commons-IO
在 Java 11 及更高版本中,可能会有更好的选择,请参阅 ZhekaKozlov 的评论。
评论
close()
zipFile.getInputStream(entry).transferTo(outputStream)
我知道它已经晚了,有很多答案,但这个 zip4j 是我用过的最好的压缩库之一。它很简单(没有锅炉代码),可以轻松处理受密码保护的文件。
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.core.ZipFile;
public static void unzip(){
String source = "some/compressed/file.zip";
String destination = "some/destination/folder";
String password = "password";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}
Maven 依赖项如下:
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
<version>1.3.2</version>
</dependency>
评论
code new File(getClass().getResource(zipFileName).getPath());
您可以查看的另一个选项是 zt-zip,可从 Maven 中心和项目页面获得 https://github.com/zeroturnaround/zt-zip
它具有标准的打包和解包功能(在流和文件系统上)+ 许多辅助方法,用于测试存档中的文件或添加/删除条目。
评论
另一种选择是 JZlib。根据我的经验,它不像 zip4J 那样“以文件为中心”,所以如果你需要处理内存中的 blob 而不是文件,你可能想看看它。
这里有一个以递归方式压缩和解压缩文件的完整示例:http://developer-tips.hubpages.com/hub/Zipping-and-Unzipping-Nested-Directories-in-Java-using-Apache-Commons-Compress
使用 zip4j 压缩/解压缩文件夹/文件的完整实现
将此依赖项添加到生成管理器。或者,从此处下载最新的 JAR 文件并将其添加到您的项目构建路径中。波纹管可以压缩和提取任何有或没有密码保护的文件或文件夹-class
import java.io.File;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import net.lingala.zip4j.core.ZipFile;
public class Compressor {
public static void zip (String targetPath, String destinationFilePath, String password) {
try {
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
if (password.length() > 0) {
parameters.setEncryptFiles(true);
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
parameters.setPassword(password);
}
ZipFile zipFile = new ZipFile(destinationFilePath);
File targetFile = new File(targetPath);
if (targetFile.isFile()) {
zipFile.addFile(targetFile, parameters);
} else if (targetFile.isDirectory()) {
zipFile.addFolder(targetFile, parameters);
} else {
//neither file nor directory
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void unzip(String targetZipFilePath, String destinationFolderPath, String password) {
try {
ZipFile zipFile = new ZipFile(targetZipFilePath);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destinationFolderPath);
} catch (Exception e) {
e.printStackTrace();
}
}
/**/ /// for test
public static void main(String[] args) {
String targetPath = "target\\file\\or\\folder\\path";
String zipFilePath = "zip\\file\\Path";
String unzippedFolderPath = "destination\\folder\\path";
String password = "your_password"; // keep it EMPTY<""> for applying no password protection
Compressor.zip(targetPath, zipFilePath, password);
Compressor.unzip(zipFilePath, unzippedFolderPath, password);
}/**/
}
有关更详细的用法,请参阅此处。
评论