Dosyaları sıkıştırmak / açmak için iyi bir Java kütüphanesi nedir? [kapalı]


232

JDK ve Apache sıkıştırma kütüphaneleri ile birlikte gelen varsayılan Zip kütüphanesine baktım ve 3 nedenden dolayı onlardan memnun değilim:

  1. Şişirilmiş ve kötü API tasarımına sahipler. Kazan plakası bayt dizi çıkışı, zip girişi, dosya akışları ve ilgili akışları kapatmak ve istisnaları yakalamak ve bayt tamponları kendi başıma taşımak için 50 satır yazmak zorunda mıyım? Neden böyle görünen Zipper.unzip(InputStream zipFile, File targetDirectory, String password = null)ve Zipper.zip(File targetDirectory, String password = null)işe yarayan basit bir API'ye sahip olamıyorum ?

  2. Sıkıştırılmış sıkıştırılmış dosya meta verilerini yok ediyor ve şifre kullanımı bozuk.

  3. Ayrıca, denediğim tüm kütüphaneler UNIX ile aldığım komut satırı zip araçlarına kıyasla 2-3 kat daha yavaştı?

Benim için (2) ve (3) küçük puanlar ama gerçekten tek satır arayüzlü iyi test edilmiş bir kütüphane istiyorum.


13
# 1'e gelince, bunun nedeni herkesin bir dosyayı bir dizine açması değil. Hep aynı desen kullanıyorsanız, neden sadece bunu ihtiyaç ve sadece kullandığınız diğerlerinden birini sarar ve yapan bir yardımcı sınıf yazmak o ?
Edward Thomson

14
@EdwardThomson çünkü kitaplık kullanmak kod yazmak, test kodu yazmak ve kodu korumaktan daha kolaydır.
Zak

11
@EdwardThomson: Argümanınız geçersiz. Python zip API'sine bakın: docs.python.org/3/library/zipfile . Dosyaları sıkıştırmak veya açmak için 1 satır kod gerekir. API'lar genel durumu çok iyi işlemeli ve zip API'sinin zip veya unzipping dışında herhangi bir kullanım durumunu düşünemiyorum.
pathikrit

7
@wrick: bir dosyayı sıkıştırmak veya bir dosyayı açmak , bir akışı sıkıştırmak veya açmaktan özel bir durumdur. API'niz ona bir akış yazmama izin vermiyorsa ve bunun yerine dosyayı API'ya besleyebilmem için bir dosyaya bir akış yazmama izin veriyorsa, API'niz beyin hasarlıdır.
Edward Thomson

52
@EdwardThomson - Güzel, bu nedenle kütüphanenin hem dosyaları hem de akışları desteklemesini sağlayın. Herkesin zamanının boşa harcanması - benimki, senin, asker ve bununla karşılaşacak diğer tüm Google çalışanları, her birimizin kendi Zip Utilities'imizi uygulamamız gerektiğini. KURU olduğu gibi, DAMLA da vardır - Diğer İnsanları Tekrar Etmeyin.
ArtOfWarfare

Yanıtlar:


291

Ben onun geç biliyorum ve çok cevap var ama bu zip4j kullandığım zipping için en iyi kütüphanelerden biridir. Basit (kazan kodu yok) ve şifre korumalı dosyaları kolayca işleyebilir.

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 bağımlılığı:

<dependency>
    <groupId>net.lingala.zip4j</groupId>
    <artifactId>zip4j</artifactId>
    <version>1.3.2</version>
</dependency>

1
org.zeroturnaround.zip.ZipException var: java.io.FileNotFoundException: images \ 001GL.JPG: açık başarısız oldu: EINVAL (Geçersiz argüman) hatası
Smit Patel

4
Android ile çalışır mı?
Ercan

1
Hayır, android ile iyi çalışmıyor, Çince dilini desteklemiyor.
Dhiraj Himani

3
Zip4J, bir giriş akışından yalnızca diskten bir zip okumayı desteklemez.
Renaud Cerrato

2
Web sitesinin bir javadocu yok gibi görünüyor.
JohnC

76

İle Apache Commons-IO 's IOUtilsbunu yapabilirsiniz:

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

Hala bazı kaynak plakası kodu, ancak sadece 1 egzotik olmayan bağımlılığı var: Commons-IO


1
Java 7 ZipEntry'den bahsettiğiniz @VitalySazanovich.
Randy

2
Teşekkürler. Ayrıca sonunda zipFile.close () gerekir.
JoshuaD

4
neden IOUtils.closeQuietly (dışarı)?
Juan Mendez

2
@JuanMendez çünkü yakın hatalar varsa, dosyanın tamamen ve doğru bir şekilde kaydedildiğinden emin olamazsınız. Ama normalde ek olarak close()acıtmaz.
vadipp

3
Bu çözüm ZipSlip'e açıktır (zip4j de etkilenir )
Marcono1234

40

Yalnızca JDK kullanarak zip dosyasını ve tüm alt klasörlerini ayıklayın:

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 dosyaları ve tüm alt klasörleri:

 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
Kapanış çağrıları en azından "nihayet" blokların içinde olmalıdır. İstisnalar iyi ele alınmaz. -> Sanýrým OP bu kütüphanenin neden kullanmasýný istedi .

4
Bu çok fazla kod. Bu 2 satırda yapılabilir.
Makky

/mnt/sdcard/final_unzip_data/Product_images\001GL.JPG: açık başarısız oldu: EINVAL (Geçersiz argüman)
Smit Patel

@Joe Michael Bunu gönderdiğin için teşekkürler dostum. Sorunumu çözdü. Ben O için +1 vereceğimextractFolder(String zipFile,String extractFolder)
OO7

Bu kod dosya özniteliklerini ve izinlerini tutmaz ... çalıştırılabilir bir uygulamayı açmak için böyle bir şey kullanırsanız, dosya izinleriyle ilgili garip hatalara hazırlıklı olun. Bu bana bir haftalık baş ağrısına mal oldu.
Renato

23

Kontrol edebileceğiniz başka bir seçenek de Maven merkezinden ve proje sayfasından https://github.com/zeroturnaround/zt-zip adresinde bulunan zt-zip.

Standart paketleme ve açma işlevine (akışlarda ve dosya sisteminde) + bir arşivdeki dosyaları test etmek veya giriş eklemek / kaldırmak için birçok yardımcı yöntem vardır.


17

Bir Klasörü / Dosyayı zip4j ile Sıkıştırmak / Açmak için Tam Uygulama


Dan kavanozu indirin burada ve eklemek proje inşa yoluna. classKörük sıkıştırmak ve birlikte veya şifre olmadan herhangi bir dosya veya klasör, çıkarabilir koruma-

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
Güzel bir cevap ve kütüphane. ZipInputStream kullanılırken 20+ dakikaya kıyasla 1868 dosyayı ayıklamak bu kitaplıkta ~ 15 saniye sürdü (bir nedenden dolayı)
Jonty800

8

Çok güzel bir proje TrueZip .

TrueZIP, sanal dosya sistemleri (VFS) için arşiv tabanlı dosyalara, sanki düz dizinlermiş gibi şeffaf erişim sağlayan Java tabanlı bir eklenti çerçevesidir

Örneğin ( web sitesinden ):

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

Kütüphane güzel görünüyor - zipinputstream / file / path verilen bir zip dosyasını nasıl açacağınız hala belli değil.
pathikrit

1
TrueZIP, akışlardan okumayı çok iyi işlemiyor gibi görünüyor.
Teo Klestrup Röijezon

5
Java 7'de yapabileceğinizle büyük ölçüde aynı değil mi? ( ZipFileSystemProvider'a bakın ).
peterh

1
@peterh: Standart JDK ZipFileSystemProvider iyi bir yanıt olacaktır. Sadece birkaç kişi yorum olarak görüyor.
iuzuz

3

Başka bir seçenek JZlib'dir . Deneyimlerime göre, zip4J'den daha az "dosya merkezli" olduğundan, dosyalar yerine bellek içi lekeler üzerinde çalışmanız gerekiyorsa, ona bir göz atmak isteyebilirsiniz.



0

Http://commons.apache.org/vfs/ adresine bir göz attınız mı? Sizin için birçok şeyi basitleştirdiğini iddia ediyor. Ama bunu bir projede hiç kullanmadım.

Ayrıca JDK veya Apache Sıkıştırma dışında Java-Native sıkıştırma kütüphanelerinin farkında değilim.

Bazı özellikleri Apache Ant'den söktüğümüzde hatırlıyorum - dahili sıkıştırma / dekompresyon için birçok faydaları var.

VFS ile örnek kod şöyle görünür:

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
Görünüşe göre VFS dosyalarındaki zip dosyaları için destek oldukça sınırlıdır: commons.apache.org/vfs/filesystems.html
TJ Crowder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.