zhaowenyu
2026-03-10 63c368aae958cb80ab02546ef2022b771411710e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.ard.inspection.utils;
 
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.Enumeration;
 
/**
 * ZIP文件解压工具类
 */
@Component
public class ZipFileUtils {
 
    private static final Logger log = LoggerFactory.getLogger(ZipFileUtils.class);
 
    @Value(value = "${inspection.chunk.zipPath}")
    private String zipPath;
 
    /**
     * 解压ZIP文件到指定目录
     * @param zipFilePath 压缩包路径
     * @param overwrite 是否覆盖已存在文件
     * @throws IOException 解压异常
     */
    public void unzip(String zipFilePath, boolean overwrite) throws IOException {
        // 校验压缩包是否存在
        File zipFile = new File(zipFilePath);
        if (!zipFile.exists()) {
            throw new FileNotFoundException("压缩包不存在:" + zipFilePath);
        }
 
        // 创建目标目录
        Path targetDir = Paths.get(zipPath);
        if (!Files.exists(targetDir)) {
            Files.createDirectories(targetDir);
        }
 
        // 使用Apache Commons Compress处理大ZIP文件
        try (ZipFile zf = new ZipFile(zipFile)) {
            Enumeration<ZipArchiveEntry> entries = zf.getEntries();
            while (entries.hasMoreElements()) {
                ZipArchiveEntry entry = entries.nextElement();
                String entryName = entry.getName();
                // 拼接解压后的文件路径
                Path entryPath = targetDir.resolve(entryName);
 
                // 跳过已存在且不覆盖的文件
                if (Files.exists(entryPath) && !overwrite) {
                    log.warn("文件已存在,跳过解压:{}", entryPath);
                    continue;
                }
 
                // 如果是目录,创建目录
                if (entry.isDirectory()) {
                    if (!Files.exists(entryPath)) {
                        Files.createDirectories(entryPath);
                    }
                    continue;
                }
 
                // 创建父目录(防止文件在子目录下)
                Path parentDir = entryPath.getParent();
                if (!Files.exists(parentDir)) {
                    Files.createDirectories(parentDir);
                }
 
                // 流式复制文件(避免内存溢出)
                try (InputStream in = zf.getInputStream(entry);
                     OutputStream out = Files.newOutputStream(entryPath)) {
                    byte[] buffer = new byte[8192]; // 8K缓冲区
                    int len;
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                    log.info("解压文件完成:{}", entryPath);
                }
            }
        } catch (Exception e) {
            log.error("解压文件失败:{}", zipFilePath, e);
            throw new IOException("解压失败:" + e.getMessage(), e);
        }
    }
 
    /**
     * 解压ZIP文件到指定目录
     * @param pathStr 删除文件夹路径
     */
    public boolean deleteZipFile(String pathStr) {
        if (pathStr == null || pathStr.isEmpty()) {
            return false;
        }
        Path path = Paths.get(pathStr);
        if (!Files.exists(path)) {
            // 路径不存在,视为删除成功
            return true;
        }
        try {
            // 遍历并反向排序,确保先删除子文件/子目录,再删除父目录
            Files.walk(path)
                    .sorted(Comparator.reverseOrder())
                    .forEach(p -> {
                        try {
                            Files.deleteIfExists(p);
                        } catch (IOException e) {
                            throw new RuntimeException("删除失败: " + p, e);
                        }
                    });
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
 
    /**
     * 根据文件大小格式化
     * @param size 文件大小
     */
    public static String formatFileSize(long size) {
        if (size <= 0) return "0 B";
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return String.format("%.2f %s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }
 
}