Java压缩和解压缩(三)Apache Commons Compress实践
Java压缩和解压缩admin 发布于:2023-03-05 00:29:11
阅读:loading
Apache Commons Compress库定义了一系列操作文件压缩和解压缩的API,用于处理多种格式的文件(zip、gzip、tar、7z、jar等等),最新版本为1.2.2,JDK最低版本限制为1.8版本,这个项目组件中的代码有许多不同的起源,根据解压文件格式的不同区分,有不同的几个实现来源。对于最基本的zip格式文件提供的功能超越了java.util.zip中的实现。
本次研究Apache Commons Compress项目组件的实现主要是针对7z格式的压缩和解压缩,但是在进行源码分析实现和官网资料的了解后发现该项目支持读取7z格式的加密文件,但不支持写入加密文件,也就是说它的API不支持创建7z格式的加密实现,参考官网地址:“https://commons.apache.org”,源码地址:“https://gitbox.apache.org/repos/asf/commons-compress.git”。
package cn.chendd.compress;
/**
* 7z格式的压缩和解压缩
*
* @author chendd
* @date 2023/3/5 12:36
*/
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZMethod;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* 7z压缩和解压缩
* 注意:Apache Commons Compress 官网说明不支持7z格式的生成带密码格式的压缩
*
* @author chendd
* @date 2022/11/18 9:28
*/
public class Compress7z {
/**
* 创建压缩文件
* @param inFile 源文件
* @param outFile 7z格式
* @throws IOException 异常处理
*/
public static void sevenZ(File inFile, File outFile) throws IOException {
try (SevenZOutputFile szos = new SevenZOutputFile(outFile)) {
szos.setContentCompression(SevenZMethod.DEFLATE);
generare7zFile(inFile, szos, inFile);
szos.finish();
}
}
/**
* 解压缩文件
* @param src7zFile 源文件
* @param outFile 输出文件
*/
public static void unSevenZ(File src7zFile, File outFile) {
unSevenZ(src7zFile, outFile, null);
}
/**
* 根据密码解压7z文件
* @param src7zFile 源文件
* @param outFile 输出文件
* @param password 密码
*/
public static void unSevenZ(File src7zFile, File outFile, String password) {
if (src7zFile == null || outFile == null) {
throw new NullPointerException("file can be not null");
}
SevenZFile sevenZFile = null;
try {
if (!src7zFile.exists()) {
throw new FileNotFoundException(src7zFile.getAbsolutePath());
}
if (StringUtils.isBlank(password)) {
sevenZFile = new SevenZFile(src7zFile);
} else {
sevenZFile = new SevenZFile(src7zFile, password.toCharArray());
}
byte[] bytes = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
SevenZArchiveEntry nextEntry = sevenZFile.getNextEntry();
do {
if (nextEntry == null) {
break;
}
if (nextEntry.isDirectory()) {
File file = new File(outFile, nextEntry.getName());
file.mkdirs();
continue;
}
File file = new File(outFile, nextEntry.getName());
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
int lens;
try (FileOutputStream outputStream = new FileOutputStream(file)) {
while ((lens = sevenZFile.read(bytes)) != -1) {
outputStream.write(bytes, 0, lens);
}
}
} while ((nextEntry = sevenZFile.getNextEntry()) != null);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
IOUtils.close(sevenZFile);
} catch (IOException ignore) {
}
}
}
/**
* 生成7z压缩文件
* @param inFile 源文件
* @param szos 输出流
* @param rootFile 根文件
* @throws IOException 异常处理
*/
private static void generare7zFile(File inFile, SevenZOutputFile szos, File rootFile) throws IOException {
if (inFile.isFile()) {
putEntryFile(szos, rootFile, inFile);
return;
}
File[] files = inFile.listFiles();
if (files == null || files.length == 0) {
putEntryEmptyFolder(szos, inFile, rootFile);
return;
}
for (File file : files) {
if (file.isDirectory()) {
generare7zFile(file, szos, rootFile);
} else {
putEntryFile(szos, file, rootFile);
}
}
}
/**
* 获取7z压缩包中的文件信息
* 注意:
* (1)未正常获取到压缩后的文件大小;
* (2)与7z等软件的文件列表对比,当前的方法一次性罗列所有的文件夹以及子孙后代的所有文件;
*
* @param src7zFile 源7z文件
* @param password 密码
* @return 文件信息列表
*/
public static List<View> view(File src7zFile, String password) {
List<View> resultList = new ArrayList<>();
try (SevenZFile sevenZFile = getSevenZFile(src7zFile, password)) {
Iterable<SevenZArchiveEntry> entries = sevenZFile.getEntries();
for (SevenZArchiveEntry entry : entries) {
View view = new View();
view.setDirectory(entry.isDirectory());
view.setFileName(entry.getName());
if (entry.getHasLastModifiedDate()) {
view.setLastModifiedTime(entry.getLastModifiedDate().getTime());
} else if (entry.getHasCreationDate()) {
view.setLastModifiedTime(entry.getCreationDate().getTime());
}
view.setUncompressedSize(entry.getSize());
long compressedSize = (long) MethodUtils.invokeMethod(entry, true, "getCompressedSize");
view.setCompressedSize(compressedSize);
resultList.add(view);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return resultList;
}
/**
* 预览压缩文件列表
* @param src7zFile 源文件
* @return 文件列表
*/
public static List<View> view(File src7zFile) {
return view(src7zFile, null);
}
/**
* 根据源文件和密码构造7z文件对象
*
* @param srcFile 源文件
* @param password 密码
* @return 7z文件对象
* @throws IOException 异常处理
*/
private static SevenZFile getSevenZFile(File srcFile, String password) throws IOException {
if (StringUtils.isEmpty(password)) {
return new SevenZFile(srcFile);
}
return new SevenZFile(srcFile, password.toCharArray());
}
/**
* 压缩至文件
* @param szos 输出流
* @param file 文件
* @param rootFile 根文件
* @throws IOException 异常处理
*/
private static void putEntryFile(SevenZOutputFile szos, File file, File rootFile) throws IOException {
SevenZArchiveEntry archiveEntry = new SevenZArchiveEntry();
boolean directory = file.isDirectory();
String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
if (StringUtils.isBlank(path)) {
archiveEntry.setName(file.getName());
} else {
archiveEntry.setName(path);
}
archiveEntry.setDirectory(directory);
szos.putArchiveEntry(archiveEntry);
try (InputStream inputStream = new FileInputStream(file)) {
szos.write(inputStream);
}
szos.closeArchiveEntry();
}
/**
* 压缩生成空文件夹
* @param szos 输出流
* @param file 文件
* @param rootFile 根文件
* @throws IOException 异常处理
*/
private static void putEntryEmptyFolder(SevenZOutputFile szos, File file, File rootFile) throws IOException {
SevenZArchiveEntry archiveEntry = new SevenZArchiveEntry();
boolean directory = file.isDirectory();
String path = StringUtils.substringAfter(file.getAbsolutePath(), rootFile.getAbsolutePath() + File.separator);
if (StringUtils.isBlank(path)) {
archiveEntry.setName(file.getName());
} else {
archiveEntry.setName(path);
}
archiveEntry.setDirectory(directory);
szos.putArchiveEntry(archiveEntry);
szos.closeArchiveEntry();
}
}
package cn.chendd.compress;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.MethodSorters;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* 7z压缩和解压缩示例
*
* @author chendd
* @date 2023/3/5 17:25
*/
@RunWith(JUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Compress7zTest {
/**
* 压缩文件
*/
@Test
public void sevenZipFile() throws IOException {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File file = new File(projectHome , "源文件/哈喽.txt");
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_哈喽.7z");
Compress7z.sevenZ(file , zipFile);
System.out.println("压缩源文件:" + file.getAbsolutePath());
System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
}
/**
* 压缩文件夹
*/
@Test
public void sevenZipFolder() throws IOException {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File file = new File(projectHome , "源文件/复杂文件夹");
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_复杂文件夹.7z");
Compress7z.sevenZ(file , zipFile);
System.out.println("压缩源文件:" + file.getAbsolutePath());
System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
}
/**
* 解压缩7z文件
*/
@Test
public void unSevenZipFile() {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_哈喽.7z");
File file = new File(projectHome , "解压缩文件夹/sevenZ_哈喽");
Compress7z.unSevenZ(zipFile , file);
System.out.println("压缩源文件:" + file.getAbsolutePath());
System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
}
/**
* 解压缩7z文件夹
*/
@Test
public void unSevenZipFolder() {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_复杂文件夹.7z");
File file = new File(projectHome , "解压缩文件夹/sevenZ_复杂文件夹");
Compress7z.unSevenZ(zipFile , file);
System.out.println("压缩源文件:" + file.getAbsolutePath());
System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
}
/**
* 解压缩带密码的7z文件【Apache Commons Compress不支持生成带密码的7z,需要自己手工创建】
* 本例中的7z文件设置了压缩文件名
*/
@Test
public void unSevenZipFolderPassword() {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_带密码_简单文件夹.7z");
File file = new File(projectHome , "解压缩文件夹/sevenZ_带密码_简单文件夹");
Compress7z.unSevenZ(zipFile , file , "https://www.chendd.cn");
System.out.println("压缩源文件:" + file.getAbsolutePath());
System.out.println("压缩后文件:" + zipFile.getAbsolutePath());
}
/**
* 预览压缩包文件列表
*/
@Test
public void view() {
File projectHome = new File(System.getProperty("user.dir")).getParentFile();
File zipFile = new File(projectHome , "压缩文件夹/sevenZ_复杂文件夹.7z");
System.out.println("预览压缩包的文件:");
List<View> list = Compress7z.view(zipFile);
list.forEach(System.out::println);
}
}
(项目示例结构)
(带密码的解压缩)
(1)本文使用开源项目Apache Commons Compress 实现的“7z”格式文件(夹)的压缩和解压缩,仅以7z格式文件的操作进行示例实践;;
(2)本文示例包含文件压缩、文件解压缩、文件夹压缩、文件夹解压缩、压缩包文件列表预览;
(4)本文示例支持压缩文件(夹)包含中文名称,支持带密码文件的解压缩,不支持生成带密码的7z压缩包;
(5)项目源码下载:源码下载.txt;
点赞