파일을 압축 / 압축 해제하기에 적합한 Java 라이브러리는 무엇입니까? [닫은]


232

JDK 및 Apache 압축 라이브러리와 함께 제공되는 기본 Zip 라이브러리를 살펴본 결과 다음과 같은 3 가지 이유에 만족하지 않습니다.

  1. 부풀어 오르고 API 디자인이 잘못되었습니다. 내가해야 할 , 내 자신에 시내와 가까운 관련 스트림 캐치 예외 및 이동 바이트 버퍼 밖으로 입력, zip 파일을 보일러 플레이트 바이트 배열 출력의 50 개 라인을 쓰기 ? 이유는 간단한 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)은 사소한 점이지만 실제로 한 줄 인터페이스로 테스트를 거친 좋은 라이브러리를 원합니다.


13
# 1에 관해서는, 모든 사람이 단순히 파일을 디렉토리에 압축 해제하지는 않기 때문입니다. 항상 같은 패턴을 사용한다면 다른 클래스 중 하나를 감싸고 필요한 것을 수행하고 사용하는 유틸리티 클래스를 작성하는 것이 어떻습니까?
— Edward Thomson

14
@EdwardThomson은 코드를 작성하고, 코드를 테스트하고, 코드를 유지하는 것보다 라이브러리를 사용하는 것이 더 쉽기 때문입니다.
— Zak

11
@EdwardThomson : 당신의 주장은 유효하지 않습니다. Python zip API docs.python.org/3/library/zipfile을보십시오 . 파일을 압축하거나 압축 해제하려면 한 줄의 코드가 필요합니다. API는 일반적인 경우를 잘 처리해야하며 압축 또는 압축 해제 외에 zip API의 유스 케이스를 생각할 수 없습니다.
— pathikrit

7
@ wrick : 파일 압축 또는 파일 압축 해제는 스트림을 압축 또는 압축 해제하는 특별한 경우입니다. API가 스트림을 쓰지 못하게하고 대신 스트림을 파일에 쓰도록하여 ​​API에 피드를 제공 할 수 있다면 API가 뇌 손상되었습니다.
— Edward Thomson

52
@EdwardThomson-좋아요, 라이브러리가 파일과 스트림을 모두 지원하도록하십시오. 우리 모두 자신의 Zip 유틸리티를 구현해야한다는 우연히도 여러분, 시간을 낭비 할 것입니다. DRY가있는 것처럼 DROP이 있습니다-다른 사람을 반복하지 마십시오.
— ArtOfWarfare

답변:


291

나는 그것을 늦게 알고 많은 답변이 있지만이 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
org.zeroturnaround.zip.ZipException이 발생했습니다. java.io.FileNotFoundException : images \ 001GL.JPG : 열기 실패 : EINVAL (잘못된 인수) 오류
— Patel Smit

4
그것은 안드로이드와 함께 작동합니까?
— Ercan

1
안드로이드에서 잘 작동하지 않으며 중국어를 지원하지 않습니다.
— Dhiraj Himani

3
Zip4J는 입력 스트림에서 디스크를 읽는 것만 지원하지 않습니다.
— Renaud Cerrato

2
웹 사이트에 javadoc이없는 것 같습니다.
— JohnC

76

함께 아파치 코 몬즈 - 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);
        }
    }
  }
}

여전히 상용구 코드이지만, 이국적이지 않은 의존성에는 Commons-IO 가 하나만 있습니다.


1
@VitalySazanovich는 Java 7 ZipEntry를 말합니다.
— 랜디

2
감사. 또한 끝에 zipFile.close ()가 필요합니다.
— JoshuaD

4
왜 IOUtils.closeQuietly (out)가 아닙니까?
— Juan Mendez

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
닫기 호출은 최소한 "최종"블록 내에 있어야합니다. 예외는 잘 처리되지 않습니다. -> OP가 라이브러리 사용을 요청한 이유의 일부라고 생각합니다 .

4
이것은 너무 많은 코드입니다. 이것은 두 줄로 이루어질 수 있습니다.
— Makky

/mnt/sdcard/final_unzip_data/Product_images\001GL.JPG : 열지 못했습니다 : EINVAL (잘못된 인수)
— Patel Patel

@Joe Michael이 게시물을 게시 해 주셔서 감사합니다. 내 문제를 해결합니다. extractFolder(String zipFile,String extractFolder)
— OO7

이 코드는 파일 속성과 권한을 유지하지 않습니다 ... 실행 가능한 응용 프로그램의 압축을 풀기 위해 이와 같은 것을 사용하는 경우 파일 권한과 관련된 이상한 오류에 대비하십시오. 이로 인해 일주일에 두통이 발생했습니다.
— Renato

23

체크 아웃 할 수있는 또 다른 옵션 은 Maven central의 https://github.com/zeroturnaround/zt-zip 에서 제공되는 zt-zip입니다.

표준 패킹 및 압축 풀기 기능 (스트림 및 파일 시스템) + 아카이브에서 파일을 테스트하거나 항목을 추가 / 제거하는 많은 도우미 메소드가 있습니다.


17

zip4j를 사용 하여 폴더 / 파일을 압축 / 압축 해제하기위한 전체 구현


에서 항아리를 다운로드 여기 및 추가 프로젝트 빌드 경로에. 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
좋은 답변과 도서관. ZipInputStream을 사용할 때 20+ 분과 비교하여이 라이브러리에서 1868 개의 파일을 추출하는 데 ~ 15 초가 걸렸습니다 (어떤 이유로 든)
— Jonty800

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 파일의 압축을 푸는 방법은 분명하지 않습니다.
— pathikrit

1
TrueZIP는 스트림에서의 읽기를 잘 처리하지 못하는 것 같습니다.
— Teo Klestrup Röijezon 2016 년

5
Java 7에서 할 수있는 것과 크게 같지 않습니까? ( ZipFileSystemProvider 참조 ).
— peterh

1
@ peterh : 표준 JDK ZipFileSystemProvider가 좋은 대답입니다. 주석으로 보는 사람은 거의 없습니다.
— iuzuz

3

다른 옵션은 JZlib 입니다. 내 경험상 zip4J보다 "파일 중심"이 적으므로 파일이 아닌 메모리 내 Blob에서 작업해야하는 경우 살펴볼 수 있습니다.



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

1
VFS 자체의 zip 파일에 대한 지원은 상당히 제한되어 있습니다. commons.apache.org/vfs/filesystems.html
— TJ Crowder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.