Java中zip文件的压缩和解压缩


=Start=

缘由:

简单记录一下如何用Java对zip文件进行压缩和解压缩,尤其是如何将特定文件添加到一个已有的zip压缩包中(不用先解压,复制,然后重压缩的方式实现)。

正文:

参考解答:

压缩和解压缩特定文件的代码基本是从 Baeldung 这里拷贝过来的,直接往已有zip压缩包中添加文件是从官网中的示例中改的。

package com.example;

import java.io.*;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @author ixyzero
 * Created on 2022-05-09
 */
public class opZip {
    public static void main(String[] args) {
        String sourceFile = "new-test-docx.docx";
        String zipFile = "test-output.zip";
        String appendFile = "new-test-xlsx.xlsx";
        String appendFile2 = "new-test-xlsx.rar";
        String unzipDir = "unzipTest";

        try {
            FileOutputStream fos = new FileOutputStream(zipFile);
            ZipOutputStream zipOut = new ZipOutputStream(fos);

            File fileToZip = new File(sourceFile);
            zipFile(fileToZip, fileToZip.getName(), zipOut);

            zipOut.close();
            fos.close();
            System.out.println("zip file success!");

            addFileToZip(appendFile, zipFile);
            addFileToZip2(appendFile2, zipFile);

            unzipFile(zipFile, unzipDir);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // https://www.baeldung.com/java-compress-and-uncompress
    private static void unzipFile(String filePath, String unzipDir) throws Exception {
        File zipFile = new File(filePath);
        File destDir = new File(unzipDir);
        byte[] buffer = new byte[1024];
        ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
        ZipEntry zipEntry = zis.getNextEntry();
        while (zipEntry != null) {
            File newFile = newFile(destDir, zipEntry);
            if (zipEntry.isDirectory()) {
                if (!newFile.isDirectory() && !newFile.mkdirs()) {
                    throw new IOException("Failed to create directory " + newFile);
                }
            } else {
                // fix for Windows-created archives
                File parent = newFile.getParentFile();
                if (!parent.isDirectory() && !parent.mkdirs()) {
                    throw new IOException("Failed to create directory " + parent);
                }

                // write file content
                FileOutputStream fos = new FileOutputStream(newFile);
                int len;
                while ((len = zis.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
                fos.close();
            }
            zipEntry = zis.getNextEntry();
        }
        zis.closeEntry();
        zis.close();
        System.out.println("unzip file success!");
    }

    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        fis.close();
    }

    public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
        File destFile = new File(destinationDir, zipEntry.getName());

        String destDirPath = destinationDir.getCanonicalPath();
        String destFilePath = destFile.getCanonicalPath();

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

        return destFile;
    }

    // work well, but only can add file not directory(files under dir can not be added)
    // https://stackoverflow.com/questions/13787318/java-util-zip-replace-a-single-zip-file
    public static void addFileToZip(String filePathStr, String zipFilePathStr) throws Exception {
        Path myFilePath = Paths.get(filePathStr);
        Path zipFilePath = Paths.get(zipFilePathStr);
        try( FileSystem fs = FileSystems.newFileSystem(zipFilePath, null) ) {
            Path fileInsideZipPath = fs.getPath(filePathStr.contains("/") ?
                    filePathStr.substring(filePathStr.lastIndexOf("/")) : "/"+filePathStr);
            Files.copy(myFilePath, fileInsideZipPath); // fileInsideZipPath 字符串的内容其实可以任意设置
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return;
    }

    // do not work, until add fs.close()
    public static void addFileToZip2(String filePathStr, String zipFilePathStr) throws Exception {
        Path myFilePath = Paths.get(filePathStr);
        Path zipFilePath = Paths.get(zipFilePathStr);
        FileSystem fs = FileSystems.newFileSystem(zipFilePath, null);
        Path fileInsideZipPath = fs.getPath(filePathStr.contains("/") ?
                filePathStr.substring(filePathStr.lastIndexOf("/")) : "/"+filePathStr);
        Files.copy(myFilePath, fileInsideZipPath);
        fs.close(); // don't forget to add this after modify try-with-resources statement
        return;
    }

}

JDK7之后,Java多了个新的语法:try-with-resources语句,可以理解为是一个声明一个或多个资源的 try语句(用分号隔开),一个资源作为一个对象,并且这个资源必须要在执行完关闭的,try-with-resources语句确保在语句执行完毕后,每个资源都被自动关闭 。

参考链接:

Zipping and Unzipping in Java
https://www.baeldung.com/java-compress-and-uncompress

How to create Zip file in Java
https://mkyong.com/java/how-to-compress-files-in-zip-format/

Package java.util.zip
https://docs.oracle.com/javase/7/docs/api/java/util/zip/package-summary.html

Copying a File or Directory
https://docs.oracle.com/javase/tutorial/essential/io/copy.html

The try-with-resources Statement
https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Java – Try with Resources
https://www.baeldung.com/java-try-with-resources

The try-with-resources statement
https://www.javatpoint.com/java-try-with-resources

java try-with-resource语句使用
https://www.jianshu.com/p/258c5ce1a2bd

深入理解 Java try-with-resource 语法糖
https://juejin.cn/post/6844903446185951240

=END=


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注