在Java中实现文件压缩主要依赖java.util.zip
包或第三方库(如Apache Commons Compress),以下是详细的实现步骤、代码示例及注意事项,涵盖ZIP和GZIP两种常见压缩格式。
Java文件压缩基础
-
核心类库
ZipOutputStream
/ZipInputStream
:用于ZIP格式压缩与解压。GZIPOutputStream
/GZIPInputStream
:用于GZIP格式压缩与解压。FileInputStream
/FileOutputStream
:读写文件数据。BufferedInputStream
/BufferedOutputStream
:提升读写效率。
-
压缩原理
- ZIP支持多文件压缩,可保留目录结构;GZIP通常用于单文件压缩。
- 压缩级别范围为0(无压缩)到9(最大压缩),需平衡压缩率与性能。
ZIP格式压缩实现
压缩单个文件
import java.io.; import java.util.zip.; public class FileCompressor { public static void zipSingleFile(String srcFile, String zipFile) throws IOException { try (FileOutputStream fos = new FileOutputStream(zipFile); ZipOutputStream zos = new ZipOutputStream(fos); FileInputStream fis = new FileInputStream(srcFile)) { ZipEntry entry = new ZipEntry(new File(srcFile).getName()); zos.putNextEntry(entry); byte[] buffer = new byte[4096]; int len; while ((len = fis.read(buffer)) > 0) { zos.write(buffer, 0, len); } } } }
关键点:
- 使用
ZipEntry
指定压缩文件的名称。 - 通过缓冲区(
byte[] buffer
)提高读写效率。
压缩多个文件或目录
public static void zipDirectory(String srcDir, String zipFile) throws IOException { try (FileOutputStream fos = new FileOutputStream(zipFile); ZipOutputStream zos = new ZipOutputStream(fos)) { File file = new File(srcDir); compressFile(file, zos, ""); } } private static void compressFile(File file, ZipOutputStream zos, String parentPath) throws IOException { if (file.isDirectory()) { // 空目录需创建ZipEntry以保留结构 zos.putNextEntry(new ZipEntry(parentPath + "/")); zos.closeEntry(); for (File child : file.listFiles()) { compressFile(child, zos, parentPath + "/" + file.getName()); } } else { try (FileInputStream fis = new FileInputStream(file)) { ZipEntry entry = new ZipEntry(parentPath + "/" + file.getName()); zos.putNextEntry(entry); byte[] buffer = new byte[4096]; int len; while ((len = fis.read(buffer)) > 0) { zos.write(buffer, 0, len); } } } }
关键点:
- 递归遍历目录,对空目录创建
ZipEntry
以保留层级结构。 - 通过
parentPath
参数维护相对路径,避免绝对路径导致压缩包移植性差。
设置压缩级别与性能优化
zos.setLevel(Deflater.BEST_COMPRESSION); // 设置最高压缩级别
性能优化策略:
| 优化方向 | 具体措施 |
|———-|———-|
| 缓冲区大小 | 使用byte[] buffer
(建议4KB或更大)减少I/O次数 |
| 多线程压缩 | 对独立文件分配线程并行压缩,但需避免共享ZipOutputStream
|
| 大文件分块 | 分段读取文件,避免内存溢出 |
GZIP格式压缩
GZIP适用于单文件压缩,不支持目录结构。
public static void gzipFile(String srcFile, String gzipFile) throws IOException { try (FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(gzipFile); GZIPOutputStream gos = new GZIPOutputStream(fos)) { byte[] buffer = new byte[4096]; int len; while ((len = fis.read(buffer)) > 0) { gos.write(buffer, 0, len); } } }
关键点:
- GZIP自动处理压缩级别(默认中等),可通过
GZIPOutputStream(fos, Deflater.BEST_COMPRESSION)
自定义。
解压操作
解压ZIP文件
public static void unzipFile(String zipFile, String destDir) throws IOException { try (FileInputStream fis = new FileInputStream(zipFile); ZipInputStream zis = new ZipInputStream(fis)) { ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { File file = new File(destDir, entry.getName()); if (entry.isDirectory()) { file.mkdirs(); } else { file.getParentFile().mkdirs(); try (FileOutputStream fos = new FileOutputStream(file)) { byte[] buffer = new byte[4096]; int len; while ((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } } } zis.closeEntry(); } } }
注意事项:
- 防止ZIP Slip漏洞(恶意路径穿透),需验证
entry.getName()
不包含等非法字符。
解压GZIP文件
public static void gunzipFile(String gzipFile, String outputFile) throws IOException { try (FileInputStream fis = new FileInputStream(gzipFile); GZIPInputStream gis = new GZIPInputStream(fis); FileOutputStream fos = new FileOutputStream(outputFile)) { byte[] buffer = new byte[4096]; int len; while ((len = gis.read(buffer)) > 0) { fos.write(buffer, 0, len); } } }
常见问题与解决方案
FAQs
Q1:如何设置压缩级别?
A1:通过ZipOutputStream.setLevel(int level)
或GZIPOutputStream(OutputStream, int level)
设置,值范围为0(无压缩)到9(最大压缩)。
Q2:中文文件名出现乱码如何解决?
A2:使用Apache Commons Compress库,并指定UTF-8编码:
ZipArchiveEntry entry = new ZipArchiveEntry(file.getName()); entry.setUnicodeExtra(true); // 启用UTF-8支持
或手动设置ZipEntry
的注释字段存储原始文件名。
- ZIP适合多文件压缩,保留目录结构;GZIP适合单文件压缩。
- 性能优化需关注缓冲区、多线程及压缩级别。
- 第三方库(如Apache Commons Compress)可解决编码、格式兼容等问题
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/68631.html