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

pat*_*rit 221 java compression zip unzip

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

  1. 它们很臃肿,API设计不好.我必须写50行锅炉板字节数组输出,zip输入,文件输出流和关闭相关流并捕获异常并自行移动字节缓冲区?为什么我不能有一个简单的API,它看起来像这样Zipper.unzip(InputStream zipFile, File targetDirectory, String password = null)Zipper.zip(File targetDirectory, String password = null)刚刚工作的?

  2. 它似乎压缩解压缩破坏文件元数据和密码处理被打破.

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

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

use*_*470 281

我知道它已经很晚了,而且有很多答案,但这个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Maven的依赖是:

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>1.3.2</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

  • 它适用于Android吗? (4认同)
  • Zip4J不支持从输入流中读取zip,仅支持从磁盘读取. (3认同)
  • 网站似乎没有javadoc. (2认同)

Geo*_*met 72

使用Apache Commons-IO,IOUtils你可以这样做:

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();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么不IOUtils.closeQuietly(out)? (4认同)
  • 此解决方案容易受到 [ZipSlip](https://snyk.io/research/zip-slip-vulnerability)(zip4j 也[受影响](https://snyk.io/vuln/SNYK-JAVA-NETLINGALAZIP4J-31679) )) (3认同)
  • 看看zip4j (2认同)
  • 谢谢。最后还需要 zipFile.close() 。 (2认同)
  • @JuanMendez因为如果关闭时出现错误,则无法确定文件是否已完全正确保存.但除了正常的'close()`之外,它不会受到伤害. (2认同)
  • 在 Java 9+ 中,您不再需要 IOUtils。只需编写“zipFile.getInputStream(entry).transferTo(outputStream)”即可。 (2认同)

Bas*_*deh 34

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

}
Run Code Online (Sandbox Code Playgroud)

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 关闭的调用应该至少在"finally"块内.例外情况处理得不好. - >我猜这是为什么OP要求_library_使用的部分原因. (7认同)
  • 这是太多的代码.这可以用2行完成. (4认同)

too*_*asr 22

您可以查看的另一个选项是来自Maven central和项目页面的zt-zip,网址https://github.com/zeroturnaround/zt-zip

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


Min*_*mal 18

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

        } 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);
    }/**/
}
Run Code Online (Sandbox Code Playgroud)

  • 一个很好的答案和图书馆。在这个库上提取 1868 个文件需要大约 15 秒,而使用 ZipInputStream 时需要 20 分钟以上(出于某种原因) (2认同)

Mic*_*ael 7

一个非常好的项目是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();
}
Run Code Online (Sandbox Code Playgroud)

  • 它与Java 7中的功能大致相同吗?(查看[ZipFileSystemProvider](http://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html)). (5认同)