使用Commons IO将目录压缩为zip文件

8

我是Java编程的初学者,目前正在编写一个应用程序,需要能够压缩和解压缩.zip文件。我可以使用以下代码,在Java中使用内置的Java zip功能以及Apache Commons IO库来解压缩zip文件:

public static void decompressZipfile(String file, String outputDir) throws IOException {
    if (!new File(outputDir).exists()) {
        new File(outputDir).mkdirs();
    }
    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 {
            InputStream in = zipFile.getInputStream(entry);
            OutputStream out = new FileOutputStream(entryDestination);
            IOUtils.copy(in, out);
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }
}

如何在不使用除我已经使用的Java标准库和Commons IO之外的任何外部库的情况下,从目录创建一个zip文件?


2
在你的情况下,zip 部分是由 java.util.Zip 完成的,commons-IO 只提供了一个关闭文件的实用程序。你是否正在寻找像上面那样的解决方案? - AdityaKeyal
是的,我正在寻找一种只使用提供的Java库和/或Commons-IO,而没有其他外部依赖项的解决方案。我已经编辑了问题文本,以使其更清晰。我相当新手,由于这段代码来自另一个SE问题,该问题将其呈现为“Commons-IO方法解压缩zipfile”,因此我错误地认为该功能由Commons-IO提供。 - StackUnderflow
4个回答

12

以下方法似乎可以成功地递归压缩一个目录:

public static void compressZipfile(String sourceDir, String outputFile) throws IOException, FileNotFoundException {
    ZipOutputStream zipFile = new ZipOutputStream(new FileOutputStream(outputFile));
    compressDirectoryToZipfile(sourceDir, sourceDir, zipFile);
    IOUtils.closeQuietly(zipFile);
}

private static void compressDirectoryToZipfile(String rootDir, String sourceDir, ZipOutputStream out) throws IOException, FileNotFoundException {
    for (File file : new File(sourceDir).listFiles()) {
        if (file.isDirectory()) {
            compressDirectoryToZipfile(rootDir, sourceDir + File.separator + file.getName(), out);
        } else {
            ZipEntry entry = new ZipEntry(sourceDir.replace(rootDir, "") + file.getName());
            out.putNextEntry(entry);

            FileInputStream in = new FileInputStream(sourceDir + file.getName());
            IOUtils.copy(in, out);
            IOUtils.closeQuietly(in);
        }
    }
}

从我的压缩代码片段中可以看到,我使用IOUtils.copy()来处理流数据传输。


第10行出现了错误,File.separator被放在了一个拼接操作之后。 - David Levy
3
这行代码有一个错误。原文代码是:FileInputStream in = new FileInputStream(sourceDir + file.getName()); 应该改为:FileInputStream in = new FileInputStream(sourceDir+File.separator + file.getName()); - shiva

3

我修复了上述错误,现在它完美运行。

    public static void compressZipfile(String sourceDir, String outputFile) throws IOException, FileNotFoundException {
    ZipOutputStream zipFile = new ZipOutputStream(new FileOutputStream(outputFile));
    Path srcPath = Paths.get(sourceDir);
    compressDirectoryToZipfile(srcPath.getParent().toString(), srcPath.getFileName().toString(), zipFile);
    IOUtils.closeQuietly(zipFile);
}

private static void compressDirectoryToZipfile(String rootDir, String sourceDir, ZipOutputStream out) throws IOException, FileNotFoundException {
    String dir = Paths.get(rootDir, sourceDir).toString();
    for (File file : new File(dir).listFiles()) {
        if (file.isDirectory()) {
            compressDirectoryToZipfile(rootDir, Paths.get(sourceDir,file.getName()).toString(), out);
        } else {
            ZipEntry entry = new ZipEntry(Paths.get(sourceDir,file.getName()).toString());
            out.putNextEntry(entry);

            FileInputStream in = new FileInputStream(Paths.get(rootDir, sourceDir, file.getName()).toString());
            IOUtils.copy(in, out);
            IOUtils.closeQuietly(in);
        }
    }
}

可能是重复的问题,链接为https://dev59.com/hX_aa4cB1Zd3GeqPzB9b#23346890 - Digao

3

看起来答案有点过时。现在已经更新为最新的Java版本。 此外,在ZIP文件中,文件名将相对于给定的压缩文件夹。在原始答案中,它们是绝对路径。

import org.apache.commons.io.IOUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class Zipper {

    public static void compressFolder(String sourceDir, String outputFile) throws IOException {
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputFile))) {
            compressDirectoryToZipFile((new File(sourceDir)).toURI(), new File(sourceDir), zipOutputStream);
        }
    }

    private static void compressDirectoryToZipFile(URI basePath, File dir, ZipOutputStream out) throws IOException {
        List<File> fileList = Files.list(Paths.get(dir.getAbsolutePath()))
                .map(Path::toFile)
                .collect(Collectors.toList());
        for (File file : fileList) {
            if (file.isDirectory()) {
                compressDirectoryToZipFile(basePath, file, out);
            } else {
                out.putNextEntry(new ZipEntry(basePath.relativize(file.toURI()).getPath()));
                try (FileInputStream in = new FileInputStream(file)) {
                    IOUtils.copy(in, out);
                }
            }
        }
    }

}

-1

基于上面的答案,完整的ZipUtils类。

public final class ZipUtils {

    private ZipUtils() {
    }

    // For testing
    public static void main(String[] args) throws IOException {
        compressFile(new File("./file.test"), new File("test1.zip"));
        compressDirectory(new File("./test1"), new File("test2.zip"));
        extractArchive(new File("./test2"), new File("test3.zip"));
    }

    public static void compressDirectory(File sourceDirectory, File zipFile) throws IOException {
        Preconditions.checkState(sourceDirectory.exists(), "Source directory is not exists: %s", sourceDirectory);
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
            compressDirectory(sourceDirectory.getAbsoluteFile(), sourceDirectory, out);
        }
    }

    private static void compressDirectory(File rootDir, File sourceDir, ZipOutputStream out) throws IOException {
        for (File file : Preconditions.checkNotNull(sourceDir.listFiles())) {
            if (file.isDirectory()) {
                compressDirectory(rootDir, new File(sourceDir, file.getName()), out);
            } else {
                String zipEntryName = getRelativeZipEntryName(rootDir, file);
                compressFile(out, file, zipEntryName);
            }
        }
    }

    private static String getRelativeZipEntryName(File rootDir, File file) {
        return StringUtils.removeStart(file.getAbsolutePath(), rootDir.getAbsolutePath());
    }

    public static void compressFile(File file, File zipFile) throws IOException {
        try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))) {
            compressFile(out, file, file.getName());
        }
    }

    private static void compressFile(ZipOutputStream out, File file, String zipEntityName) throws IOException {
        ZipEntry entry = new ZipEntry(zipEntityName);
        out.putNextEntry(entry);

        try (FileInputStream in = new FileInputStream(file)) {
            IOUtils.copy(in, out);
        }
    }

    public static void extractArchive(File targetDirectory, File zipFile) throws IOException {
        try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
            extractStream(targetDirectory, zis);
        }
    }

    private static void extractStream(File targetDirectory, ZipInputStream zis) throws IOException {
        ZipEntry zipEntry = zis.getNextEntry();
        while (zipEntry != null) {
            extractEntry(targetDirectory, zis, zipEntry);
            zipEntry = zis.getNextEntry();
        }
        zis.closeEntry();
    }

    private static void extractEntry(File targetDirectory, ZipInputStream zis, ZipEntry zipEntry) throws IOException {
        File newFile = newFile(targetDirectory, zipEntry);
        if (zipEntry.isDirectory()) {
            FileUtils.forceMkdir(newFile);
        } else {
            FileUtils.forceMkdirParent(newFile);
            try (FileOutputStream fos = new FileOutputStream(newFile)) {
                IOUtils.copy(zis, fos);
            }
        }
    }

    private static File newFile(File targetDirectory, ZipEntry zipEntry) throws IOException {
        File targetFile = new File(targetDirectory, zipEntry.getName());

        String targetDirPath = targetDirectory.getCanonicalPath();
        String targetFilePath = targetFile.getCanonicalPath();

        if (!targetFilePath.startsWith(targetDirPath + File.separator)) {
            throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
        }

        return targetFile;
    }
}

你说“Full Class”,但导入语句在哪里?“Preconditions”是指什么? - Wolf359

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接