파일을 압축 / 압축 해제하기에 적합한 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.