0%

zip压缩

Java 压缩与解压缩操作详解:ZIP 与 GZIP 实践

在 Java 中,处理压缩文件是常见需求,尤其是在文件传输、存储优化等场景。JDK 内置了对 ZIP 和 GZIP 格式的支持,通过 java.util.zip 包中的类可实现压缩和解压缩操作。本文将详细介绍 ZIP 和 GZIP 的使用方法,包括单文件 / 多文件压缩、文件夹递归压缩及解压缩的具体实现。

ZIP 压缩与解压缩

ZIP 是一种广泛使用的归档格式,支持将多个文件或文件夹压缩到一个 .zip 文件中,且可保留目录结构。Java 中通过 ZipInputStream(解压缩)和 ZipOutputStream(压缩)实现 ZIP 操作。

ZIP 解压缩(ZipInputStream

ZipInputStream 用于读取 ZIP 文件中的条目(文件或文件夹),通过 getNextEntry() 遍历所有条目,再通过输入流读取具体内容。

核心步骤:
  1. 创建 ZipInputStream 关联 ZIP 文件输入流。
  2. 循环调用 getNextEntry() 获取每个 ZipEntry(条目)。
  3. 对每个条目,通过 ZipInputStream 读取数据(若为文件夹则跳过内容读取)。
  4. 处理完成后调用 closeEntry() 关闭当前条目,最终关闭流。
示例:解压缩 ZIP 文件到指定目录
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
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipUncompressor {
/**
* 解压缩 ZIP 文件到目标目录
* @param zipFilePath ZIP 文件路径
* @param destDir 目标目录
*/
public static void unzip(String zipFilePath, String destDir) throws IOException {
// 创建目标目录(不存在则创建)
File destDirFile = new File(destDir);
if (!destDirFile.exists()) {
destDirFile.mkdirs();
}

try (ZipInputStream zis = new ZipInputStream(
new BufferedInputStream(new FileInputStream(zipFilePath)),
StandardCharsets.UTF_8)) { // 指定编码(解决中文乱码)

ZipEntry entry;
// 遍历所有条目
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
File entryFile = new File(destDirFile, entryName);

if (entry.isDirectory()) {
// 若为文件夹,创建目录
entryFile.mkdirs();
} else {
// 若为文件,读取内容并写入目标文件
// 确保父目录存在
File parentDir = entryFile.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}

try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(entryFile))) {
byte[] buffer = new byte[1024];
int len;
while ((len = zis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
}
}
zis.closeEntry(); // 关闭当前条目
}
}
}

public static void main(String[] args) throws IOException {
unzip("test.zip", "unzip_result");
System.out.println("解压缩完成!");
}
}
注意事项:
  • 中文乱码ZipInputStream 构造器需指定编码(如 StandardCharsets.UTF_8),避免条目名称中文乱码。
  • 目录处理:通过 entry.isDirectory() 判断是否为文件夹,需创建对应目录结构。

ZIP 压缩(ZipOutputStream

ZipOutputStream 用于将文件或文件夹压缩为 ZIP 文件,通过 putNextEntry() 写入条目信息,再写入具体内容。

核心步骤:
  1. 创建 ZipOutputStream 关联目标 ZIP 文件输出流。
  2. 对每个需要压缩的文件 / 文件夹,创建 ZipEntry 并调用 putNextEntry()
  3. 写入文件内容(文件夹无需写入内容,仅创建条目)。
  4. 调用 closeEntry() 关闭当前条目,最终关闭流。
示例:压缩文件或文件夹为 ZIP
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
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipCompressor {
/**
* 压缩文件或文件夹为 ZIP
* @param sourcePath 源文件/文件夹路径
* @param zipFilePath 目标 ZIP 文件路径
*/
public static void zip(String sourcePath, String zipFilePath) throws IOException {
File sourceFile = new File(sourcePath);
if (!sourceFile.exists()) {
throw new FileNotFoundException("源文件/文件夹不存在:" + sourcePath);
}

try (ZipOutputStream zos = new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream(zipFilePath)),
StandardCharsets.UTF_8)) { // 指定编码

// 递归压缩(根据源是否为文件夹处理)
if (sourceFile.isDirectory()) {
// 压缩文件夹(传入父路径为空,避免顶级目录冗余)
compressDirectory(zos, sourceFile, "");
} else {
// 压缩单个文件
compressFile(zos, sourceFile, "");
}
}
}

/**
* 递归压缩文件夹
* @param zos ZIP 输出流
* @param dir 待压缩文件夹
* @param parentEntryName 父条目名称(用于构建条目路径)
*/
private static void compressDirectory(ZipOutputStream zos, File dir, String parentEntryName) throws IOException {
File[] files = dir.listFiles();
if (files == null) {
return; // 空文件夹
}

// 构建当前文件夹的条目名称(末尾加斜杠表示文件夹)
String dirEntryName = parentEntryName + dir.getName() + File.separator;
zos.putNextEntry(new ZipEntry(dirEntryName));
zos.closeEntry(); // 文件夹条目无需内容,直接关闭

// 递归处理子文件/子文件夹
for (File file : files) {
if (file.isDirectory()) {
compressDirectory(zos, file, dirEntryName);
} else {
compressFile(zos, file, dirEntryName);
}
}
}

/**
* 压缩单个文件
* @param zos ZIP 输出流
* @param file 待压缩文件
* @param parentEntryName 父条目名称(用于构建条目路径)
*/
private static void compressFile(ZipOutputStream zos, File file, String parentEntryName) throws IOException {
String entryName = parentEntryName + file.getName();
zos.putNextEntry(new ZipEntry(entryName)); // 写入条目信息

// 写入文件内容
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
zos.write(buffer, 0, len);
}
}
zos.closeEntry(); // 关闭当前条目
}

public static void main(String[] args) throws IOException {
// 压缩单个文件
zip("test.txt", "single_file.zip");
// 压缩文件夹
zip("docs", "docs.zip");
System.out.println("压缩完成!");
}
}
注意事项:
  • 条目路径:通过 parentEntryName 维护目录结构,确保解压后目录层级正确。
  • 文件夹标识:文件夹条目名称需以 File.separator(如 /\)结尾,否则解压时可能被识别为文件。

GZIP 压缩与解压缩

GZIP 是一种用于压缩单个文件的格式(不支持多文件或文件夹),压缩后文件通常以 .gz 为扩展名。Java 中通过 GZIPInputStream(解压缩)和 GZIPOutputStream(压缩)实现。

GZIP 压缩(GZIPOutputStream

示例:压缩单个文件为 GZIP
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
import java.io.*;
import java.util.zip.GZIPOutputStream;

public class GzipCompressor {
/**
* 压缩单个文件为 GZIP
* @param sourceFilePath 源文件路径
* @param gzipFilePath 目标 GZIP 文件路径
*/
public static void gzip(String sourceFilePath, String gzipFilePath) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFilePath));
GZIPOutputStream gzos = new GZIPOutputStream(
new BufferedOutputStream(new FileOutputStream(gzipFilePath)))) {

byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
gzos.write(buffer, 0, len);
}
}
}

public static void main(String[] args) throws IOException {
gzip("data.txt", "data.txt.gz");
System.out.println("GZIP 压缩完成!");
}
}

GZIP 解压缩(GZIPInputStream

示例:解压缩 GZIP 文件
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
import java.io.*;
import java.util.zip.GZIPInputStream;

public class GzipUncompressor {
/**
* 解压缩 GZIP 文件
* @param gzipFilePath GZIP 文件路径
* @param destFilePath 目标文件路径
*/
public static void ungzip(String gzipFilePath, String destFilePath) throws IOException {
try (GZIPInputStream gzis = new GZIPInputStream(
new BufferedInputStream(new FileInputStream(gzipFilePath)));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destFilePath))) {

byte[] buffer = new byte[1024];
int len;
while ((len = gzis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
}
}

public static void main(String[] args) throws IOException {
ungzip("data.txt.gz", "data_ungzipped.txt");
System.out.println("GZIP 解压缩完成!");
}
}

ZIP 与 GZIP 的对比

特性 ZIP GZIP
支持对象 多文件、文件夹(保留目录结构) 仅单个文件
压缩效率 适中(支持存储未压缩文件) 较高(通常比 ZIP 压缩率更高)
用途 多文件归档(如软件安装包、资源包) 单个大文件压缩(如日志、备份文件)
实现复杂度 较高(需处理条目和目录结构) 较低(直接读写文件内容)
常见扩展名 .zip .gz

最佳实践

  1. 缓冲流提升性能:压缩 / 解压缩时,使用 BufferedInputStreamBufferedOutputStream 减少 IO 次数,显著提升性能。
  2. 处理中文乱码:ZIP 操作需指定编码(如 UTF-8),避免条目名称或内容乱码。
  3. 递归压缩文件夹:ZIP 压缩文件夹时,需递归处理子文件和子目录,确保目录结构完整。
  4. 异常处理:使用 try-with-resources 自动关闭流,避免资源泄露;捕获 IO 异常并友好提示。
  5. 大文件处理:对于 GB 级大文件,可增大缓冲区大小(如 8KB 或 16KB),平衡内存占用和效率

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10