java 解压多级目录 zip 压缩包

关键在于  

zipEntry.isDirectory()  

用于判断压缩包内的条目是不是文件夹

  /**
     * 解压 zip
     *
     * @param zipFile
     * @param descDir
     */
    public static void unpack(File zipFile, File descDir) {
        try (ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK"))) {
            if (!descDir.exists()) {
                descDir.mkdirs();
            }
            ZipEntry zipEntry = null;
            File outfile = null;
            while ((zipEntry = inputStream.getNextEntry()) != null) {
                outfile = checkFileDir(descDir, zipEntry.getName());
                if (zipEntry.isDirectory()) {
                    outfile.mkdirs();
                } else {
                    OutputStream os = null;
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(new File(descDir, zipEntry.getName())));
                        IOUtils.copy(inputStream, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * zip 条目覆盖漏洞校验
     * 防止压缩包内文件名称包含路径 例:../a.jpg
     *
     * @param destDir
     * @param fileName
     * @return
     */
    public static File checkFileDir(File destDir, String fileName) {
        File destFile = new File(destDir, fileName);
        String destDirPath = "";
        String destFilePath = "";
        try {
            destDirPath = destDir.getCanonicalPath();
            destFilePath = destFile.getCanonicalPath();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        if (!destFilePath.startsWith(destDirPath + File.separator)) {
            throw new RuntimeException("文件不在许可目录内!");
        }
        // 防止压缩包一级目录只有文件夹时,解压报错找不到文件
        File parentDir = destFile.getParentFile();
        if(!parentDir.exists()){
	        parentDir.mkdirs();
        }
        return destFile;
    }

解压过程提示报错:java.lang.IllegalArgumentException: MALFORMED

java.lang.IllegalArgumentException: MALFORMED
	at java.util.zip.ZipCoder.toString(ZipCoder.java:58)
	at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:300)
	at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:122)
原因

windows环境下,默认字符集为GBK,ZipFile默认使用UTF-8字符集,当文件名存在中文时,处理时就会报错

解决方法

创建 ZipInputStream 时,设置字符集为GBK

ZipInputStream inputStream = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("GBK")

Java中,解压多级压缩包(如.zip、.rar等)并处理嵌套的加密文件通常需要使用第三方库,因为标准的Java库并不直接支持复杂的加密操作。Zip4j 和 JSmoothIDM 是两个常用的库,它们可以用于解压包括密码保护在内的压缩文件。 以下是使用Zip4j的一个示例,假设你已经有了密码: ```java import org.apache.commons.compress.utils.IOUtils; import org.zip4j.unzip.UnZIPFile; import org.zip4j.unzip.ZipFileHeader; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.List; public class PasswordProtectedUnzipping { public static void main(String[] args) { try { // 压缩文件路径 String zipPath = "path_to_your_encrypted_zip"; // 密码 String password = "your_password"; UnZIPFile unzipFile = new UnZIPFile(zipPath); if (!unzipFile.isEncrypted()) { throw new RuntimeException("The file is not encrypted."); } unzipFile.setPassword(password); List<ZipFileHeader> headers = unzipFile.getHeaders(); for (ZipFileHeader header : headers) { if (header.isDirectory()) continue; // 忽略目录 InputStream in = null; FileOutputStream out = null; try { in = unzipFile.getInputStream(header); File outputDir = new File("output_directory"); outputDir.mkdirs(); String entryName = header.getName(); out = new FileOutputStream(outputDir.getPath() + "/" + entryName); IOUtils.copy(in, out); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) try { in.close(); } catch (IOException ignore) {} if (out != null) try { out.close(); } catch (IOException ignore) {} } } unzipFile.close(); } catch (Exception e) { e.printStackTrace(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值