压缩/解压缩文件的优秀Java库是什么?

时间:2012-02-17 08:17:29

标签: compression zip unzip java

我查看了JDK和Apache压缩库附带的默认Zip库,我对它们不满意有三个原因:

  1. 它们很臃肿,API设计不好。我必须write 50 lines of boiler plate byte array output, zip input, file out streams and close relevant streams and catch exceptions and move byte buffers on my own?为什么我不能使用看起来像这个Zipper.unzip(InputStream zipFile, File targetDirectory, String password = null)Zipper.zip(File targetDirectory, String password = null)的简单API?

  2. 似乎拉链解压缩破坏文件元数据和密码处理已被破坏。

  3. 此外,与我使用UNIX获得的命令行zip工具相比,我尝试的所有库都慢2-3倍?

  4. 对我来说(2)和(3)是次要的,但我真的想要一个带有单线界面的测试好的库。

9 个答案:

答案 0 :(得分:271)

我知道它已经很晚了并且有很多答案,但是这个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>

答案 1 :(得分:68)

使用Apache Commons-IOIOUtils,您可以执行此操作:

java.util.zip.ZipFile zipFile = new ZipFile(file);
try {
  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();
        InputStream in = zipFile.getInputStream(entry);
        OutputStream out = new FileOutputStream(entryDestination);
        IOUtils.copy(in, out);
        IOUtils.closeQuietly(in);
        out.close();
    }
  }
} finally {
  zipFile.close();
}

它仍然是一些样板代码,但它只有1个非外来依赖:Commons-IO

答案 2 :(得分:32)

仅使用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();
        }
    }
}

答案 3 :(得分:21)

您可以查看的另一个选项是 zt-zip ,可从Maven中心和项目页面https://github.com/zeroturnaround/zt-zip

获取

它具有标准的打包和解包功能(在流和文件系统上)+许多辅助方法来测试存档中的文件或添加/删除条目。

答案 4 :(得分:14)

使用zip4j

压缩/解压缩文件夹/文件的完整实施

将jar从hereadd it下载到您的项目构建路径。 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);
            }

        } 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 only
    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);
    }/**/
}

答案 5 :(得分:7)

一个非常好的项目是TrueZip

  

TrueZIP是一个基于Java的虚拟文件系统(VFS)插件框架,它提供对存档文件的透明访问,就好像它们只是普通的目录一样

例如(来自website):

File file = new TFile("archive.tar.gz/README.TXT");
OutputStream out = new TFileOutputStream(file);
try {
   // Write archive entry contents here.
   ...
} finally {
   out.close();
}

答案 6 :(得分:2)

另一个选项是JZlib。根据我的经验,它不像zip4J那样“以文件为中心”,所以如果你需要处理内存中的blob而不是文件,你可能需要看看它。

答案 7 :(得分:0)

你看过http://commons.apache.org/vfs/了吗?它声称为您简化了很多事情。但我从未在项目中使用它。

我也不了解除JDK或Apache Compression之外的Java-Native压缩库。

我记得有一次我们从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();
}

答案 8 :(得分:0)

这里有一个完整的示例,用于递归地压缩和解压缩文件: http://developer-tips.hubpages.com/hub/Zipping-and-Unzipping-Nested-Directories-in-Java-using-Apache-Commons-Compress