欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java GZip 基于磁盘实现压缩和解压的方法

程序员文章站 2022-09-29 23:41:38
  gzip是常用的无损压缩算法实现,在linux中较为常见,像我们在linux安装软件时,基本都是.tar.gz格式。.tar.gz格式文件需要先对目录内文件进行tar压缩,...

  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) 在大文件、文件数量较大时,提倡使用磁盘压缩和解压方式。过大文件对服务会造成过度的负载,磁盘压缩和解压可以缓解这种压力。