【问题标题】:Compress directory into a zipfile with Commons IO使用 Commons IO 将目录压缩成 zip 文件
【发布时间】:2014-06-12 15:49:21
【问题描述】:

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

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

除了我已经在使用的库之外,我将如何从不使用外部库的目录中创建 zip 文件? (Java 标准库和 Commons IO)

【问题讨论】:

  • 在您的情况下,zip 部分是由 java.util.Zip commons-IO 完成的,它只是提供了一个关闭文件的实用程序。您是否正在寻找类似上述的解决方案?
  • 是的,我正在寻找一种解决方案,它只使用提供的 Java 库和/或 Commons-IO,而不使用其他外部依赖项。我已经编辑了问题文本以更清楚地说明这一点。我很新,因为这段代码来自另一个 SE 问题,将其呈现为“解压缩 zipfile 的 Commons-IO 方法”,我错误地认为该功能是由 Commons-IO 提供的。

标签: java zip apache-commons-io


【解决方案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);
                }
            }
        }
    }

}

【讨论】:

    【解决方案2】:

    全班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;
        }
    }
    

    【讨论】:

    • 您说“全班”,但导入语句在哪里? “先决条件”指的是什么?
    【解决方案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);
            }
        }
    }
    

    【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

    • 第 10 行出现错误,File.separator 已太迟放入一个 concat。
    • 这一行有一个错误.. 在这一行 FileInputStream in = new FileInputStream(sourceDir + file.getName());应该是 FileInputStream in = new FileInputStream(sourceDir+File.separator + file.getName());
    猜你喜欢
    • 2018-02-24
    • 2012-11-07
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    相关资源
    最近更新 更多