本文目录导读:

Java中实现压缩文件解压,最常用的就是 Zip 格式,Java标准库中的 java.util.zip 包提供了原生支持,对于 RAR 格式,Java标准库不支持,需要借助第三方库(如 Apache Commons Compress 或 junrar)。
下面我为你提供 Java 解压 Zip 和 RAR 文件的核心案例代码。
解压 Zip 文件 (Java原生实现)
这是最常用且无需引入任何第三方依赖的方法。
import java.io.*;
import java.nio.charset.Charset;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipDecompressor {
/**
* 解压ZIP文件
* @param zipFilePath 要解压的zip文件路径
* @param destDirPath 解压到目标目录的路径
* @param charset 编码格式 (中文文件名建议使用 GBK 或 UTF-8)
* @throws IOException 如果发生I/O错误
*/
public static void unzip(String zipFilePath, String destDirPath, Charset charset) throws IOException {
File destDir = new File(destDirPath);
// 如果目标目录不存在,则创建
if (!destDir.exists()) {
destDir.mkdirs();
}
// 使用 ZipInputStream 读取文件 (推荐处理大文件)
try (ZipInputStream zis = new ZipInputStream(
new FileInputStream(zipFilePath), charset)) {
ZipEntry entry;
byte[] buffer = new byte[1024];
// 遍历zip内的每一个条目
while ((entry = zis.getNextEntry()) != null) {
// 构建目标文件路径 (注意防止路径穿越漏洞)
File newFile = new File(destDir, entry.getName());
String destDirCanonical = destDir.getCanonicalPath();
String newFileCanonical = newFile.getCanonicalPath();
// 安全检查:防止压缩包内包含 ".." 导致的路径穿越
if (!newFileCanonical.startsWith(destDirCanonical + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + entry.getName());
}
if (entry.isDirectory()) {
// 如果是目录,创建目录
newFile.mkdirs();
} else {
// 如果是文件,确保父目录存在
newFile.getParentFile().mkdirs();
// 写入文件内容
try (FileOutputStream fos = new FileOutputStream(newFile)) {
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
zis.closeEntry(); // 关闭当前条目
}
}
}
// 简便方法 (默认UTF-8编码)
public static void unzip(String zipFilePath, String destDirPath) throws IOException {
unzip(zipFilePath, destDirPath, Charset.forName("UTF-8"));
}
// 测试示例
public static void main(String[] args) {
try {
String zipFile = "D:/test/example.zip";
String destDir = "D:/test/output/";
// 尝试UTF-8 (Linux/Mac) 或 GBK (Windows中文系统)
try {
unzip(zipFile, destDir, Charset.forName("UTF-8"));
} catch (Exception e) {
System.out.println("UTF-8解压失败,尝试GBK...");
unzip(zipFile, destDir, Charset.forName("GBK"));
}
System.out.println("解压完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码要点说明:
- 路径穿越防护:
ZipSlip漏洞是解压时常见的安全问题,恶意压缩包可能包含 文件名覆盖其他文件。 - 编码问题:Windows上很多压缩软件使用GBK编码,Linux/Mac使用UTF-8,建议先尝试UTF-8,失败再尝试GBK。
ZipInputStream:适合大文件,流式读取,不会把所有文件加载到内存。
解压 RAR 文件 (使用 Apache Commons Compress)
RAR是专有格式,Java标准库不支持,推荐使用 org.apache.commons.compress。
Maven依赖 (pom.xml):
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.26.2</version> <!-- 请使用最新稳定版 -->
</dependency>
代码示例:
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.rar.RarArchiveInputStream;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
public class RarDecompressor {
public static void unrar(String rarFilePath, String destDirPath) throws Exception {
File destDir = new File(destDirPath);
if (!destDir.exists()) {
destDir.mkdirs();
}
// 创建解压输入流
try (ArchiveInputStream ais = new ArchiveStreamFactory()
.createArchiveInputStream(ArchiveStreamFactory.RAR,
new BufferedInputStream(new FileInputStream(rarFilePath)))) {
ArchiveEntry entry;
while ((entry = ais.getNextEntry()) != null) {
// 构建目标文件路径 (同样需要路径穿越防护)
File newFile = new File(destDir, entry.getName());
String destDirCanonical = destDir.getCanonicalPath();
String newFileCanonical = newFile.getCanonicalPath();
if (!newFileCanonical.startsWith(destDirCanonical + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + entry.getName());
}
if (entry.isDirectory()) {
newFile.mkdirs();
} else {
newFile.getParentFile().mkdirs();
// 使用Commons Compress提供的IOUtils简化写入
try (OutputStream os = new FileOutputStream(newFile)) {
IOUtils.copy(ais, os);
}
}
}
}
}
// 测试示例
public static void main(String[] args) {
try {
unrar("D:/test/example.rar", "D:/test/output_rar/");
System.out.println("RAR解压完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:
RarArchiveInputStream目前只能解压 RAR v3 格式,对于 RAR v5 格式,commons-compress的纯Java实现支持有限,可能需要使用junrar或调用系统unrar命令行。
解压常见问题的总结与建议
| 文件格式 | 推荐方案 | 注意事项 |
|---|---|---|
| .zip | 标准库 java.util.zip |
注意编码(GBK/UTF-8);注意路径穿越漏洞 |
| .tar.gz / .tar.bz2 | Apache Commons Compress | TarArchiveInputStream + GzipCompressorInputStream |
| .7z | Apache Commons Compress (需额外依赖 xz 或 lzma) |
依赖于 org.tukaani:xz 库 |
| .rar | Apache Commons Compress / junrar | RAR v4支持较好,RAR v5可能需用命令行 |
性能建议:
- 对于超大文件 (如几百MB以上的ZIP),使用
ZipInputStream流式处理,避免使用ZipFile一次性加载条目索引。 - 对于多文件压缩包,可以考虑使用多线程解压不同文件(注意线程安全,每个文件单独输出流)。
如果你有具体的文件格式或特殊场景(如加密的ZIP、分卷压缩),欢迎进一步提问,我可以给出更针对性的方案。