文章目录
- 概要
- 技术详解
- Java代码实例
- 小结
概要
7z、zip、gz、tar、rar以及tar.gz是不同的文件压缩和归档格式,它们各自具有独特的特点和用途。本篇文章通过Java对文件进行加密压缩/解压、目录及多文件归档等进行阐述。
技术详解
- 7z:
- 定义:7z是一种新的压缩格式,由7-Zip软件发布,采用GNU LGPL协议。
- 特点:拥有目前最高的压缩比,支持Unicode文件名,具有公开的结构编辑功能和强大的AES-256加密,可更改和配置压缩算法,最高支持16EB(16000000000GB)的文件压缩。
- 使用场景:适用于需要高压缩比的场景,如存储大量数据或进行网络传输时。
- zip:
- 定义:zip是一种广泛使用的压缩文件格式,由菲尔·卡茨(Phil Katz)于1989年创建。
- 特点:采用DEFLATE等压缩算法,文件体积小,支持多文件合并,具有目录结构,便于传输和存储。但原生不支持Unicode文件名,可能导致部分文件共享困难。
- 使用场景:适用于文件和文件夹的打包和压缩,是网络和本地存储的常用选择。
- gz(通常与tar结合使用形成tar.gz):
- 定义:gz是gzip命令生成的压缩文件格式。
- 特点:gzip是一种无损数据压缩程序,常用于UNIX和类UNIX系统中。
- 使用场景:通常与tar命令结合使用,形成tar.gz格式,用于Linux系统中的文件打包和压缩。
- tar:
- 定义:tar是一种常用的文件打包格式,在Linux和Unix系统中广泛使用。
- 特点:可以将多个文件和目录合并成一个文件,方便存储和传输。但tar本身并不进行压缩,只是进行归档。
- 使用场景:适用于需要将多个文件和目录组合成一个单独文件的场景。
- rar:
- 定义:rar是一种文件压缩与归档的私有文件格式,由WinRAR软件发布。
- 特点:具有较高的压缩比,支持分卷压缩、固实压缩和恢复记录功能,还提供了加密功能。但RAR是收费的。
- 使用场景:适用于需要高压缩比和加密保护的场景。
- tar.gz:
- 定义:tar.gz是tar命令打包文件后,再通过gzip命令进行压缩得到的文件格式。
- 特点:结合了tar的打包功能和gzip的压缩功能,可以有效地减小文件大小,方便传输和存储。
- 使用场景:广泛应用于Linux系统中的文件打包、压缩和管理等方面。
Java代码实例
- tar文件解压归档
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* String outputTarFile = "output.tar";
String[] filesToAdd = {"file1.txt", "file2.txt"}; // 要添加到 tar 文件中的文件路径
*/
public static File compressTar( String outputTarFile, String[] filesToAdd) {
try (FileOutputStream fos = new FileOutputStream(outputTarFile);
TarArchiveOutputStream taos = new TarArchiveOutputStream(fos)) {
for (String filePath : filesToAdd) {
File file = new File(filePath);
TarArchiveEntry entry = new TarArchiveEntry(file, filePath);
taos.putArchiveEntry(entry);
try (InputStream fis = new FileInputStream(file)) {
IOUtils.copy(fis, taos);
}
taos.closeArchiveEntry();
}
System.out.println("Tar 文件创建成功: " + outputTarFile);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
解压tar文件,original 源文件,outPath 解压路径
*/
public static List<File> unCompressTar(File original, String outPath) throws IOException {
List<File> files = new ArrayList<>();
try (TarArchiveInputStream tais =
new TarArchiveInputStream(new FileInputStream(original), "UTF-8")) {
TarArchiveEntry tarArchiveEntry = null;
while ((tarArchiveEntry = tais.getNextTarEntry()) != null) {
String name = tarArchiveEntry.getName();
File tarFile = new File(outPath, name);
if (tarArchiveEntry.isDirectory()) {
tarFile.mkdirs();
continue;
}
if (!tarFile.getParentFile().exists()) {
tarFile.getParentFile().mkdirs();
}
try (BufferedOutputStream bos =
new BufferedOutputStream(new FileOutputStream(tarFile))) {
int read = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((read = tais.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
bos.flush();
bos.close();
}
}
getFiles(new File(outPath), files);
}
return files;
}
- tar.gz代码实例
实际就是先对gzip处理,然后对tar解压。
public static List<File> unCompressArchiveGz(File archive, String outPath) throws IOException {
String fileName = archive.getName();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(archive))) {
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(outPath + File.separator + fileName))) {
GzipCompressorInputStream gcis = new GzipCompressorInputStream(bis);
byte[] buffer = new byte[BUFFER_SIZE];
int read = -1;
while ((read = gcis.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
bos.flush();
bos.close();
}
}
//调用上述解压tar的方法
return unCompressTar(outPath + File.separator + fileName);
}
- rar 压缩与解压
- rar4
这里使用的是com.github.junrar,但是其最新版本只支持rar1-rar4,不支持最新的rar5算法
github例子:官方例子
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>{version}</version>
</dependency>
//优雅的解压文件
Junrar.extract("/tmp/foo.rar", "/tmp", "password");
//无密码
Junrar.extract("/tmp/foo.rar", "/tmp");
- 针对rar5 的支持需要使用sevenzipjbinding
参考博客代码:https://blog.csdn.net/qq_41841482/article/details/124864484
但是上述博客没有讲针对加密的rar5文件的解压处理,需要参考官方的demo用例,进一步的改写。
官方测试用例:sevenzipjbinding用例,就是在打开文件时需要加入密码即可。
- ZIP解压
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ExtraDataRecord;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.AesKeyStrength;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
public static List<File> unzip(File zipFile, String dest, String password) throws ZipException, IOException {
ZipFile zFile = new ZipFile(zipFile);
//设置GBK解决文件名和中文路径乱码的问题
zFile.setCharset(InternalZipConstants.CHARSET_UTF_8);
List<FileHeader> headers = zFile.getFileHeaders();
for (FileHeader fileHeader : headers) {
if (!fileHeader.isDirectory()) {
String fileName = fileHeader.getFileName();
if (isMessy(fileName)) {
zFile = new ZipFile(zipFile);
zFile.setCharset(Charset.forName(UTF8));
break;
}
}
}
File dstFile = null;
if (dest.endsWith(File.separator) == false) {
dest = dest + File.separator;
}
dstFile = new File(dest);
if (dstFile.isDirectory() && !dstFile.exists()) {
dstFile.mkdirs();
}
if (zFile.isEncrypted()) {
if (null == password || password.length() == 0) {
return new ArrayList<>();
}
zFile.setPassword(getPassword(password));
}
// zFile.extractAll(dstFile.getAbsolutePath());
List<FileHeader> headerList = zFile.getFileHeaders();
List<File> extractedFileList = new ArrayList<File>();
for (FileHeader fileHeader : headerList) {
if (!fileHeader.isDirectory()) {
String fileNameFromExtraData = getFileNameFromExtraData(fileHeader);
zFile.extractFile(fileHeader, dest, fileNameFromExtraData);
File newFile = new File(dest + fileNameFromExtraData);
extractedFileList.add(newFile);
}
}
return extractedFileList;
}
- 7z的解压处理
/**
* 解压缩7z文件
*
* @param file 压缩包文件
* @param targetPath 目标文件夹
*/
public static List<File> decompress7Z(File file, String targetPath, String password) throws Exception {
List<File> files = new ArrayList<>();
SevenZFile sevenZFile = null;
OutputStream outputStream = null;
try {
if (StringUtils.isNoneBlank(password)) {
sevenZFile = new SevenZFile(file, password.getBytes());
//sevenZFile = new SevenZFile(file,getPasswordBytes(password));
} else {
sevenZFile = new SevenZFile(file);
}
// 创建输出目录
File targetDir = new File(targetPath);
targetDir.mkdirs();
SevenZArchiveEntry entry;
while ((entry = sevenZFile.getNextEntry()) != null) {
if (entry.isDirectory()) {
new File(targetPath + File.separator + entry.getName()).mkdirs();
} else {
new File(targetPath + File.separator + entry.getName()).getParentFile().mkdirs();
outputStream = new FileOutputStream(new File(targetPath + File.separator + entry.getName()));
int len = 0;
byte[] b = new byte[2048];
while ((len = sevenZFile.read(b)) != -1) {
outputStream.write(b, 0, len);
}
outputStream.flush();
outputStream.close();
}
}
getFiles(targetDir, files);
} finally {
try {
if (sevenZFile != null) {
sevenZFile.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return files;
}
小结
格式 | 压缩效率 | 压缩速度 | 解压速度 | 兼容性 | 安全性 | 特殊功能 |
---|---|---|---|---|---|---|
7z | 高 | 较慢 | 较快 | 较好(需7-Zip支持) | 强(AES-256加密) | 高压缩比,支持分卷压缩 |
zip | 中 | 快 | 快 | 广(跨平台支持) | 中(支持加密,但密码可能泄露) | 支持多文件合并,目录结构 |
gz (gzip) | 中(常与tar结合使用) | 中 | 中 | 好(Linux/Unix系统广泛支持) | 弱 | 无(仅压缩,需与tar结合形成tar.gz) |
tar | 无(仅打包,不压缩) | 快(打包速度) | 快(解压速度) | 好(Linux/Unix系统广泛支持) | 无 | 文件打包,便于存储和传输 |
rar | 高 | 中 | 中 | 较好(需WinRAR等支持) | 强(AES加密) | 支持分卷压缩,固实压缩,恢复记录 |
tar.gz | 高(tar打包后gzip压缩) | 中 | 中 | 好(Linux/Unix系统广泛支持) | 弱 | 打包和压缩结合,适用于Linux系统管理 |