在java(JDK)中我们可以使用ZipOutputStream去创建zip压缩文件,(参考我之前写的文章 使用java API进行zip递归压缩文件夹以及解压 ),也可以使用GZIPOutputStream去创建gzip(gz)压缩文件,但是java中没有一种官方的API可以去创建tar.gz文件。所以我们需要使用到第三方库Apache Commons Compress去创建.tar.gz文件。

在pom.xml中,我们可以通过如下的maven坐标引入commons-compress。

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
</dependency>

解释说明

  1. tar文件准确的说是打包文件,将文件打包到一个tar文件中,文件名后缀是.tar
  2. Gzip是将文件的存储空间压缩保存,文件名后缀是.gz
  3. tar.gz.tgz通常是指将文件打包到一个tar文件中,并将它使用Gzip进行压缩。

如果您阅读完本文觉得对您有帮助的话,请给我一个赞,您的支持是我不竭的创作动力!

一、将两个文件打包到tar.gz

下面的这个例子是将2个文件打包为tar.gz压缩文件。下文代码中的流操作使用了try-with-resources语法,所以不用写代码手动的close流。

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.junit.jupiter.api.Test; import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List; public class TarGzTest { @Test
void testFilesTarGzip() throws IOException {
//输入文件,被压缩文件
Path path1 = Paths.get("/home/test/file-a.xml");
Path path2 = Paths.get("/home/test/file-b.txt");
List<Path> paths = Arrays.asList(path1, path2); //输出文件压缩结果
Path output = Paths.get("/home/test/output.tar.gz"); //OutputStream输出流、BufferedOutputStream缓冲输出流
//GzipCompressorOutputStream是gzip压缩输出流
//TarArchiveOutputStream打tar包输出流(包含gzip压缩输出流)
try (OutputStream fOut = Files.newOutputStream(output);
BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { //遍历文件list
for (Path path : paths) {
//该文件不是目录或者符号链接
if (!Files.isRegularFile(path)) {
throw new IOException("Support only file!");
}
//将该文件放入tar包,并执行gzip压缩
TarArchiveEntry tarEntry = new TarArchiveEntry(
path.toFile(),
path.getFileName().toString()); tOut.putArchiveEntry(tarEntry);
Files.copy(path, tOut); tOut.closeArchiveEntry();
}
//for循环完成之后,finish-tar包输出流
tOut.finish();
}
}
}

file-a.xmlfile-b.txt打包到output.tar文件中,并使用gzip对这个tar包进行压缩。可以使用如下命令查看tar包里面包含的文件。

$ tar -tvf /home/test/output.tar.gz
-rw-r--r-- 0/0 23546 2020-08-17 12:07 file-a.xml
-rw-r--r-- 0/0 34 2020-08-17 12:36 file-b.txt

二、将一个文件夹压缩为tar.gz

下面的例子将一个文件夹,包含其子文件夹的文件或子目录,打包为tar,并使用gzip进行压缩。最终成为一个tar.gz打包压缩文件。

其核心原理是:使用到Files.walkFileTree依次遍历文件目录树中的文件,将其一个一个的添加到TarArchiveOutputStream.输出流。

@Test
void testDirTarGzip() throws IOException {
// 被压缩打包的文件夹
Path source = Paths.get("/home/test");
//如果不是文件夹抛出异常
if (!Files.isDirectory(source)) {
throw new IOException("请指定一个文件夹");
} //压缩之后的输出文件名称
String tarFileName = "/home/" + source.getFileName().toString() + ".tar.gz"; //OutputStream输出流、BufferedOutputStream缓冲输出流
//GzipCompressorOutputStream是gzip压缩输出流
//TarArchiveOutputStream打tar包输出流(包含gzip压缩输出流)
try (OutputStream fOut = Files.newOutputStream(Paths.get(tarFileName));
BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) {
//遍历文件目录树
Files.walkFileTree(source, new SimpleFileVisitor<Path>() { //当成功访问到一个文件
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attributes) throws IOException { // 判断当前遍历文件是不是符号链接(快捷方式),不做打包压缩处理
if (attributes.isSymbolicLink()) {
return FileVisitResult.CONTINUE;
} //获取当前遍历文件名称
Path targetFile = source.relativize(file); //将该文件打包压缩
TarArchiveEntry tarEntry = new TarArchiveEntry(
file.toFile(), targetFile.toString());
tOut.putArchiveEntry(tarEntry);
Files.copy(file, tOut);
tOut.closeArchiveEntry();
//继续下一个遍历文件处理
return FileVisitResult.CONTINUE;
} //当前遍历文件访问失败
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.printf("无法对该文件压缩打包为tar.gz : %s%n%s%n", file, exc);
return FileVisitResult.CONTINUE;
} });
//for循环完成之后,finish-tar包输出流
tOut.finish();
}
}

三、解压tar.gz压缩文件

下面一个例子说明如何解压一个tar.gz文件,具体内容请看代码注释。

@Test
void testDeCompressTarGzip() throws IOException {
//解压文件
Path source = Paths.get("/home/test/output.tar.gz");
//解压到哪
Path target = Paths.get("/home/test2"); if (Files.notExists(source)) {
throw new IOException("您要解压的文件不存在");
} //InputStream输入流,以下四个流将tar.gz读取到内存并操作
//BufferedInputStream缓冲输入流
//GzipCompressorInputStream解压输入流
//TarArchiveInputStream解tar包输入流
try (InputStream fi = Files.newInputStream(source);
BufferedInputStream bi = new BufferedInputStream(fi);
GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
TarArchiveInputStream ti = new TarArchiveInputStream(gzi)) { ArchiveEntry entry;
while ((entry = ti.getNextEntry()) != null) { //获取解压文件目录,并判断文件是否损坏
Path newPath = zipSlipProtect(entry, target); if (entry.isDirectory()) {
//创建解压文件目录
Files.createDirectories(newPath);
} else {
//再次校验解压文件目录是否存在
Path parent = newPath.getParent();
if (parent != null) {
if (Files.notExists(parent)) {
Files.createDirectories(parent);
}
}
// 将解压文件输入到TarArchiveInputStream,输出到磁盘newPath目录
Files.copy(ti, newPath, StandardCopyOption.REPLACE_EXISTING); }
}
} } //判断压缩文件是否被损坏,并返回该文件的解压目录
private Path zipSlipProtect(ArchiveEntry entry,Path targetDir)
throws IOException { Path targetDirResolved = targetDir.resolve(entry.getName());
Path normalizePath = targetDirResolved.normalize(); if (!normalizePath.startsWith(targetDir)) {
throw new IOException("压缩文件已被损坏: " + entry.getName());
} return normalizePath;
}

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

使用Java API进行tar.gz文件及文件夹压缩解压缩的更多相关文章

  1. Delphi - Windows系统下,Delphi调用API函数和7z.dll动态库,自动把文件压缩成.tar.gz格式的文件

    项目背景 应欧美客户需求,需要将文件压缩成.tar.gz格式的文件,并上传给客户端SFTP服务器. 你懂的,7-Zip软件的显著特点是文件越大压缩比越高,在Linux系统上相当于我们Windows系统 ...

  2. xlslib安装, aclocal-1.13: command not found, 安装升级autoconf-2.65.tar.gz, automake-1.13.tar.gz两个文件

    问题1: $ make CDPATH="${ZSH_VERSION+.}:" && cd . && aclocal-1.13 -I m4 /bin/ ...

  3. 第一章:pip 安装 tar.gz 结尾的文件 和 .whl 结尾的文件

    1. 假如后缀中还有 .tar.gz 的文件通过 pip 命令进行安装步骤. .单击 .tar.gz结尾的文件,并且对文件进行解压,进入到解压目录中,通过python命令进行安装. 命令如下:在dos ...

  4. 如何将文件压缩成.tar.gz格式的文件

    1.下载“7-ZIP“这个软件 2.安装7-ZIP以后,直接在你想要打包的文件上点右键菜单,会有一个7-ZIP的子菜单栏,类似WinRAR和WinZIP的那种右键菜单.然后选“7-ZIP”->“ ...

  5. Linux压缩解压 tar.gz格式的文件.查看tomcat是否运行

    tar命令详解 -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用 ...

  6. linux中解压缩并安装.tar.gz后缀的文件

    1.解压缩: Linux下以tar.gz为扩展名的软件包,是用tar程序打包并用gzip程序压缩的软件包.要安装这种软件包,需要先对软件包进行解压缩,使用“tar -zxfv filename.tar ...

  7. 【java】 java 解压tar.gz读取内容

    package com.xwolf.stat.util; import com.alibaba.druid.util.StringUtils; import com.alibaba.fastjson. ...

  8. 不解压查看tar.gz包内文件

    通过tar命令备份.解压缩文件,也可在不解压缩文件时查看包内的文件信息. 使用如下参数: tar -ztvf file.tar.gz 将列出所有包内的文件列表,包括目录 -z, --gzip, --g ...

  9. tar、7z(7zip)压缩/解压缩指令的使用

    本文介绍tar.7z指令的使用方法 tar指令 在Linux中,使用的最多的压缩/解压缩指令就是tar指令了. tar指令用来将多个文件/目录结构打包.在实际使用中,往往使用tar对压缩的支持,即同时 ...

随机推荐

  1. git问题解决

    1.如果系统中有一些配置文件在服务器上做了配置修改,然后后续开发又新添加一些配置项的时候, 在发布这个配置文件的时候,会发生代码冲突: error: Your local changes to the ...

  2. shell变量子串

    表达式 说明 ${parameter} 返回变量$parameter的内容 ${#parameter} 返回变量$parameter内容的长度(按字符),也适用于特殊变量 ${parameter:of ...

  3. Android系统前台进程,可见进程,服务进程,后台进程,空进程的优先级排序

    1.前台进程 前台进程是Android中最重要的进程,在最后被销毁,是目前正在屏幕上显示的进程和一些系统进程,也就是和用户正在交互的进程. 2.可见进程 可见进程指部分程序界面能够被用户看见,却不在前 ...

  4. Python字典内置函数和方法

    Python字典内置函数和方法: 注:使用了 items.values.keys 返回的是可迭代对象,可以使用 list 转化为列表. len(字典名): 返回键的个数,即字典的长度 # len(字典 ...

  5. 7-Pandas之索引调整方法

    一.调整索引.修改列标签 1.调整索引的两种情况: 重新索引 设置新的索引 (1)重新索引 在Pandas对象中,其实索引也是一个对象,所以可对其进行修改. 例如:df.index=['a','b', ...

  6. python小题目汇总

    1.编程计算两个日期之间的天数与周数 Python时间处理---dateutil模块: dateutil模块主要有两个函数,parser和rrule. 其中parser是根据字符串解析成datetim ...

  7. PHP date_modify() 函数

    ------------恢复内容开始------------ 实例 修改时间戳.增加 15 天: <?php$date=date_create("2013-05-01");d ...

  8. 死磕HashMap

    前言 HashMap是Java中最常用的集合类框架,也是Java语言中非常典型的数据结构,同时也是我们需要掌握的数据结构,更重要的是进大厂面试必问之一. 数组特点 存储区间是连续,且占用内存严重,空间 ...

  9. 【机器学习的Tricks】随机权值平均优化器swa与pseudo-label伪标签

    文章来自公众号[机器学习炼丹术] 1 stochastic weight averaging(swa) 随机权值平均 这是一种全新的优化器,目前常见的有SGB,ADAM, [概述]:这是一种通过梯度下 ...

  10. 基于asp.net core 从零搭建自己的业务框架(二)

    前言 对于项目的迭代,如何降低复杂性的要求高于性能以及技术细节的 一个易用的项目,才能迭代到比拼性能,最后拼刺刀的阶段 传统单体项目,都是传统三层,直接请求响应的模式,这类称为Rpc模式,易用性上非常 ...