ファイルをzip / unzipするための適切なJavaライブラリは何ですか?[閉まっている]


232

JDKとApache圧縮ライブラリに付属しているデフォルトのZipライブラリを確認したところ、3つの理由で不満を感じています。

  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)はマイナーなポイントですが、1行のインターフェースを備えたテスト済みの優れたライブラリが本当に必要です。


13
#1に関しては、誰もが単にファイルをディレクトリに解凍しているわけではないためです。常に同じパターンを使用している場合は、他の1つをラップし、必要なことを行うユーティリティクラスを作成して、それを使用するだけではどうでしょうか。
エドワードトムソン

14
@EdwardThomsonは、コードを記述してコードをテストし、コードを保守するよりもライブラリを使用する方が簡単だからです。
Zak

11
@EdwardThomson:引数が無効です。Python zip API:docs.python.org/3/library/zipfileを見てください。ファイルを圧縮または解凍するには、1行のコードが必要です。APIは一般的なケースを非常にうまく処理する必要があり、zip圧縮または解凍以外のzip APIの使用例は考えられません。
pathikrit 2013

7
@wrick:ビュンファイルをか、解凍ファイルは、ストリームをビュンや解凍の特殊なケースです。APIでストリームを書き込むことができず、代わりにストリームをファイルに書き込んで、それをAPIにフィードできるようにした場合、APIは脳に損傷を受けます。
エドワードトムソン

52
@EdwardThomson-わかりました。ライブラリでファイルとストリームの両方をサポートするようにしてください。私、あなた、あなたの質問者、そしてこれに出くわす他のすべてのGoogle社員が私たち自身のZipユーティリティを実装しなければならないというのは、みんなの時間の無駄です。DRYがあるように、DROP-他の人を繰り返さないでください。
ArtOfWarfare 2013年

回答:


291

私は遅いことを知っており、答えはたくさんありますが、このzip4jは、私が使用した圧縮に最適なライブラリの1つです。そのシンプル(ボイラーコードなし)で、パスワードで保護されたファイルを簡単に処理できます。

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
org.zeroturnaround.zip.ZipException:java.io.FileNotFoundException:images \ 001GL.JPG:open failed:EINVAL(Invalid argument)error
Smit Patel

4
Androidで動作しますか?
Ercan、2015

1
それはアンドロイドでうまく機能していません、それは中国語をサポートしていません。
Dhiraj Himani

3
Zip4Jは、ディスクからのみ、入力ストリームからのzipの読み取りをサポートしていません。
Renaud Cerrato、2016

2
ウェブサイトにjavadocがないようです。
JohnC 16

76

Apache Commonsの-IO「S 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);
        }
    }
  }
}

それはまだいくつかのボイラープレートコードですが、唯一の非エキゾチックな依存関係があります:Commons-IO


1
@VitalySazanovichあなたはJava 7 ZipEntryを参照しています。
ランディ

2
ありがとう。最後にzipFile.close()も必要です。
JoshuaD 2015年

4
なぜIOUtils.closeQuietly(out)でないのですか?
ファンメンデス

2
@JuanMendezは、閉じるときにエラーが発生した場合、ファイルが完全に正しく保存されたかどうかを確認できないためです。しかし、通常close()に加えて、それは害を及ぼすことはありません。
vadipp

3
このソリューションはZipSlipに対して脆弱です(zip4jも影響を受けます
Marcono1234

40

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

7
closeの呼び出しは、少なくとも「finally」ブロック内にある必要があります。例外はうまく処理されていません。-> OPがライブラリの使用を要求した理由の一部だと思います。

4
これはコードが多すぎます。これは2行で行うことができます。
Makky 2013

/mnt/sdcard/final_unzip_data/Product_images\001GL.JPG:オープンに失敗しました:EINVAL(無効な引数)
Smit Patel

@Joe Michaelこれを投稿してくれたbuddyに感謝します。それは私の問題を解決します。私はのためのuに1をあげるextractFolder(String zipFile,String extractFolder)
OO7

このコードはファイルの属性と権限を保持しません...このようなものを使用して実行可能なアプリケーションを解凍する場合は、ファイルの権限に関する奇妙なエラーに備えてください。これは私に頭痛の週を費やしました。
Renato

23

チェックアウトできるもう1つのオプションは、https://github.com/zeroturnaround/zt-zipの Mavenセントラルおよびプロジェクトページから入手できるzt-zipです

標準のパッキングおよびアンパッキング機能(ストリーム上およびファイルシステム上)+アーカイブ内のファイルをテストしたり、エントリを追加/削除したりする多くのヘルパーメソッドを備えています。


17

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

1
いい答えとライブラリ。このライブラリでは1868ファイルの抽出に
最大

8

非常に優れたプロジェクトはTrueZipです。

TrueZIPは、仮想ファイルシステム(VFS)用のJavaベースのプラグインフレームワークで、単なるディレクトリであるかのようにアーカイブファイルに透過的にアクセスできます。

たとえば(ウェブサイトから):

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

ライブラリは見栄えがいい-zipinputstream / file / pathを指定してzipファイルを単純に解凍する方法はまだ明らかではない。
パティクリット

1
TrueZIPはストリームからの読み取りをうまく処理しないようです。
Teo KlestrupRöijezon2013年

5
Java 7でできることとほとんど同じではありませんか?(ZipFileSystemProviderを見てください)。
peterh 2014年

1
@peterh:標準のJDK ZipFileSystemProviderが適切な答えになります。コメントとしてそれを見る人はほとんどいない。
iuzuz 2018年

3

別のオプションはJZlibです。私の経験では、zip4Jよりも「ファイル中心」ではないため、ファイルではなくメモリ内のBLOBで作業する必要がある場合は、それを確認することをお勧めします。



0

あなたは見ていました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();
}

1
VFSのもの自体のzipファイルのサポートはかなり制限されているようです:commons.apache.org/vfs/filesystems.html
TJ Crowder
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.