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

时间:2014-04-27 01:32:55

标签: java zip apache-commons-io

我是Java编程的初学者,目前正在编写一个必须能够压缩和解压缩.zip文件的应用程序。我可以使用以下代码使用内置的Java zip功能以及Apache Commons IO库解压缩Java中的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);
        }
    }
}

除了我以前使用的外,我如何使用除外部库之外的目录创建zipfile? (Java标准库和Commons IO)

4 个答案:

答案 0 :(得分:9)

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

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()来处理流数据传输。

答案 1 :(得分: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);
        }
    }
}

答案 2 :(得分:1)

看起来答案有点过时了。现在将其刷新为最新的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);
                }
            }
        }
    }

}

答案 3 :(得分:0)

基于上述答案的全类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;
    }
}