7

I am a beginner at programming with Java and am currently writing an application which must be able to compress and decompress .zip files. I can use the following code to decompress a zipfile in Java using the built-in Java zip functionality as well as the Apache Commons IO library:

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

How would I go about creating a zipfile from a directory using no external libraries other than what I am already using? (Java standard libraries and Commons IO)

4

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

于 2014-04-28T16:56:13.960 回答
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);
        }
    }
}
于 2017-08-31T03:55:41.950 回答
2

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

}
于 2020-05-13T22:11:22.283 回答
-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;
    }
}
于 2018-10-31T03:54:28.980 回答