Java GZip 基于磁盘实现压缩和解压的方法
作者:超哥说码
这篇文章主要介绍了Java GZip 基于磁盘实现压缩和解压,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考需要的朋友可以参考下
GZip是常用的无损压缩算法实现,在Linux中较为常见,像我们在Linux安装软件时,基本都是.tar.gz格式。.tar.gz格式文件需要先对目录内文件进行tar压缩,然后使用GZip进行压缩。
本文针对基于磁盘的压缩和解压进行演示,演示只针对一层目录结构进行,多层目录只需递归操作进行即可。
Maven依赖
org.apache.commons: commons-compress: 1.19: 此依赖封装了很多压缩算法相关的工具类,提供的API还是相对比较底层,我们今天在它的基础上做进一步封装。
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.19</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
工具类
其实,在通常情况下,我们都是在磁盘上进行压缩和解压操作的,这样虽然增加了操作的复杂度,但是却无形中避免了一些问题。
工具类针对.tar.gz格式提供了compressByTar、decompressByTar、compressByGZip、decompressByGZip四个方法,用于处理.tar.gz格式压缩文件,代码如下:
package com.arhorchin.securitit.compress.gzip; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.apache.commons.compress.utils.IOUtils; import org.apache.log4j.Logger; /** * @author Securitit. * @note 基于磁盘以GZIP算法进行压缩和解压工具类. */ public class GZipDiskUtil { /** * logger. */ private static Logger logger = Logger.getLogger(GZipDiskUtil.class); /** * UTF-8字符集. */ public static String CHARSET_UTF8 = "UTF-8"; /** * 使用TAR算法进行压缩. * @param sourceFolderPath 待进行压缩的文件夹路径. * @param targetTarFilePath 压缩后的TAR文件存储目录. * @return 压缩是否成功. * @throws Exception 压缩过程中可能发生的异常. */ public static boolean compressByTar(String sourceFolderPath, String targetTarFilePath) throws Exception { // 变量定义. File sourceFolderFile = null; FileOutputStream targetTarFos = null; TarArchiveOutputStream targetTartTaos = null; TarArchiveEntry targetTarTae = null; try { // 压缩变量初始化. sourceFolderFile = new File(sourceFolderPath); targetTarFos = new FileOutputStream(new File(targetTarFilePath)); targetTartTaos = new TarArchiveOutputStream(targetTarFos); // 将文件添加到ZIP条目中. for (File file : sourceFolderFile.listFiles()) { try (FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis);) { targetTarTae = new TarArchiveEntry(file); targetTarTae.setName(file.getName()); targetTartTaos.putArchiveEntry(targetTarTae); targetTartTaos.write(IOUtils.toByteArray(bis)); targetTartTaos.closeArchiveEntry(); } } } catch (Exception ex) { logger.info("GZipDiskUtil.compressByTar.", ex); return false; } finally { if (targetTartTaos != null) targetTartTaos.close(); if (targetTarFos != null) targetTarFos.close(); } return true; } /** * 使用TAR算法进行解压. * @param sourceTarPath 待解压文件路径. * @param targetFolderPath 解压后文件夹目录. * @return 解压是否成功. * @throws Exception 解压过程中可能发生的异常. */ public static boolean decompressByTar(String sourceTarPath, String targetFolderPath) throws Exception { // 变量定义. FileInputStream sourceTarFis = null; TarArchiveInputStream sourceTarTais = null; TarArchiveEntry sourceTarTae = null; File singleEntryFile = null; try { // 解压定义初始化. sourceTarFis = new FileInputStream(new File(sourceTarPath)); sourceTarTais = new TarArchiveInputStream(sourceTarFis); // 条目解压缩至指定文件夹目录下. while ((sourceTarTae = sourceTarTais.getNextTarEntry()) != null) { singleEntryFile = new File(targetFolderPath + File.separator + sourceTarTae.getName()); try (FileOutputStream fos = new FileOutputStream(singleEntryFile); BufferedOutputStream bos = new BufferedOutputStream(fos);) { bos.write(IOUtils.toByteArray(sourceTarTais)); } } } catch (Exception ex) { logger.info("GZipDiskUtil.decompressByTar.", ex); return false; } finally { if (sourceTarTais != null) sourceTarTais.close(); if (sourceTarFis != null) sourceTarFis.close(); } return true; } /** * 使用GZIP算法进行压缩. * @param sourceFilePath 待进行压缩的文件路径. * @param targetGZipFilePath 压缩后的GZIP文件存储目录. * @return 压缩是否成功. * @throws Exception 压缩过程中可能发生的异常. */ public static boolean compressByGZip(String sourceFilePath, String targetGZipFilePath) throws IOException { // 变量定义. FileInputStream sourceFileFis = null; BufferedInputStream sourceFileBis = null; FileOutputStream targetGZipFileFos = null; BufferedOutputStream targetGZipFileBos = null; GzipCompressorOutputStream targetGZipFileGcos = null; try { // 压缩变量初始化. sourceFileFis = new FileInputStream(new File(sourceFilePath)); sourceFileBis = new BufferedInputStream(sourceFileFis); targetGZipFileFos = new FileOutputStream(targetGZipFilePath); targetGZipFileBos = new BufferedOutputStream(targetGZipFileFos); targetGZipFileGcos = new GzipCompressorOutputStream(targetGZipFileBos); // 采用commons-compress提供的方式进行压缩. targetGZipFileGcos.write(IOUtils.toByteArray(sourceFileBis)); } catch (Exception ex) { logger.info("GZipDiskUtil.compressByGZip.", ex); return false; } finally { if (targetGZipFileGcos != null) targetGZipFileGcos.close(); if (targetGZipFileBos != null) targetGZipFileBos.close(); if (targetGZipFileFos != null) targetGZipFileFos.close(); if (sourceFileBis != null) sourceFileBis.close(); if (sourceFileFis != null) sourceFileFis.close(); } return true; } /** * 使用GZIP算法进行解压. * @param sourceGZipFilePath 待解压文件路径. * @param targetFilePath 解压后文件路径. * @return 解压是否成功. * @throws @throws Exception 解压过程中可能发生的异常. */ public static boolean decompressByGZip(String sourceGZipFilePath, String targetFilePath) throws IOException { // 变量定义. FileInputStream sourceGZipFileFis = null; BufferedInputStream sourceGZipFileBis = null; FileOutputStream targetFileFos = null; GzipCompressorInputStream sourceGZipFileGcis = null; try { // 解压变量初始化. sourceGZipFileFis = new FileInputStream(new File(sourceGZipFilePath)); sourceGZipFileBis = new BufferedInputStream(sourceGZipFileFis); sourceGZipFileGcis = new GzipCompressorInputStream(sourceGZipFileBis); targetFileFos = new FileOutputStream(new File(targetFilePath)); // 采用commons-compress提供的方式进行解压. targetFileFos.write(IOUtils.toByteArray(sourceGZipFileGcis)); } catch (Exception ex) { logger.info("GZipDiskUtil.decompressByGZip.", ex); return false; } finally { if (sourceGZipFileGcis != null) sourceGZipFileGcis.close(); if (sourceGZipFileBis != null) sourceGZipFileBis.close(); if (sourceGZipFileFis != null) sourceGZipFileFis.close(); if (targetFileFos != null) targetFileFos.close(); } return true; } }
工具类测试
在Maven依赖引入正确的情况下,复制上面的代码到项目中,修改package,可以直接使用,下面我们对工具类进行简单测试。测试类代码如下:
package com.arhorchin.securitit.compress.gzip; import com.arhorchin.securitit.compress.gzip.GZipDiskUtil; /** * @author Securitit. * @note GZipDiskUtil工具类测试. */ public class GZipDiskUtilTester { public static void main(String[] args) throws Exception { GZipDiskUtil.compressByTar("C:/Users/Administrator/Downloads/个人文件/2020-07-13/files", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.tar"); GZipDiskUtil.compressByGZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.tar", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.tar.gz"); GZipDiskUtil.decompressByGZip("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk.tar.gz", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk-untar.tar"); GZipDiskUtil.decompressByTar("C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk-untar.tar", "C:/Users/Administrator/Downloads/个人文件/2020-07-13/disk-untar"); } }
运行测试后,通过查看disk.tar、disk.tar.gz、disk-untar.tar和解压的目录,可以确认工具类运行结果无误。
总结
1) 在小文件、文件数量较小且较为固定时,提倡使用内存压缩和解压方式。使用内存换时间,减少频繁的磁盘操作。《Java GZip 基于内存实现压缩和解压》
2) 在大文件、文件数量较大时,提倡使用磁盘压缩和解压方式。过大文件对服务会造成过度的负载,磁盘压缩和解压可以缓解这种压力。