java 7zip解压_Apache Commons Compress介绍-JAVA压缩解压7z文件

江新
2023-12-01

7zip(下面简称7z)是由Igor Pavlov所开发的一种压缩格式,主要使用的压缩算法是LZMA/LZMA2。7z是一种压缩比非常高的格式,这与其压缩算法LZMA有直接关系,所以很多大文件都是用7z进行压缩的,比如游戏之类;高压缩比并非只有好处,就是7z的压缩速度非常慢(解压速度尚可)-当然,所有压缩算法都类似:高压缩比往往是解压速度慢,这实际上可以理解为CPU与内存/硬盘之间的trade off,后面我会详细聊一下压缩背后的原理与算法。

Commons Compress是少数支持7z压缩/解压的JAVA库(据我所知除了Commons Compress就只有XZ Utils了),其API也相对友好。

与zip格式不同,commons compress在解压7z时只提供了SevenZFile类,并未提供SevenZInputStream进行逐个解压的接口,这与7z文件的格式、算法都有关系,这里不再展开说明了。

好了,废话不多说,我们进入主题:

查看7z中的所有文件

我们可以通过sevenZFile.getEntries()查看7z中的所有文件,包括文件名等属性都可以在SevenZArchiveEntry中查看。相关代码如下:

SevenZFile sevenZFile = new SevenZFile(new File("/root/test.7zip"));

final Iterable entries = sevenZFile.getEntries();

for (SevenZArchiveEntry entry : entries) {

System.out.println(entry.getName());

System.out.println(entry.getCompressedSize()); // 文件压缩后大小 System.out.println(entry.getSize()); // 文件大小}

解压全部文件

解压全部文件时可以通过sevenZFile.getNextEntry遍历所有文件并进行解压,比如我要将位于/root/test.7zip位置的文件,全部解压到/tmp/output目录下,代码如下:

try (SevenZFile sevenZFile = new SevenZFile(new File("/root/test.7zip"))) {

byte[] buffer = new byte[4096];

SevenZArchiveEntry entry;

while ((entry = sevenZFile.getNextEntry()) != null) {

if (entry.isDirectory()) {

continue;

}

File outputFile = new File("/tmp/output/" + entry.getName());

if (!outputFile.getParentFile().exists()) {

outputFile.getParentFile().mkdirs();

}

try (FileOutputStream fos = new FileOutputStream(outputFile)) {

while (sevenZFile.read(buffer) > 0) {

fos.write(buffer);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

解压特定文件

可以通过sevenZFile.getEntries(),获得所有文件后,通过遍历找到需要解压的zip文件,调用SevenZFile.getInputStream获取其InputStream,进行解压,比如需要将/root/test.7zip压缩包中,文件名为targetFile的文件,解压到/tmp/output/targetFile文件中,代码如下:

SevenZFile sevenZFile = new SevenZFile(new File("/root/test.7zip"));

final Iterable entries = sevenZFile.getEntries();

InputStream inputStream = null;

for (SevenZArchiveEntry entry : entries) {

if (entry.getName().equals("targetFile")) {

inputStream = sevenZFile.getInputStream(entry);

}

}

// 读取input stream即可完成解压byte[] buffer = new byte[4096];

File outputFile = new File("/tmp/output/targetFile");

try (FileOutputStream fos = new FileOutputStream(outputFile)) {

while (inputStream.read(buffer) > 0) {

fos.write(buffer);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

注意:7z解压特定文件(也叫随机访问)是Compress的1.20版本以后才支持的特性

解压内存中的文件

Compress的所有压缩,都可以处理硬盘及内存中的文件,7z也不例外,这在网络IO等场景下非常实用,使用也很简单:

// 通过网络IO或其他途径,将7z文件读入内存byte[] data = XXX

SevenZFile sevenZFile = new SevenZFile(new SeekableInMemoryByteChannel(data));

注意:如果文件较大时,读入内存可能消耗很多内存资源

解压分卷7z文件

分卷文件解压也十分简单:

SevenZFile sevenZFile = new SevenZFile(MultiReadOnlySeekableByteChannel

.forFiles(new File("/root/test.7z.001"), new File("/root/test.7z.002")));

// 剩余代码类似XXX

注意:传入MultiReadOnlySeekableByteChannel.forFiles的7z分卷文件,需要按照正确的顺序排列

压缩

Compress压缩7z文件,是通过xz utils实现的,并且xz在Compress的POM中是可选依赖,因此,如果要使用Compress压缩7z文件,需要在POM中手动依赖xz utils

org.tukaani

xz

1.8

压缩功能相对解压,没有那么多选择,具体可以参见下面代码中的注释:

File dir = new File("/root/dir");

File output = new File(dir, "test.7z");

final Date accessDate = new Date();

final Calendar cal = Calendar.getInstance();

cal.add(Calendar.HOUR, -1);

final Date creationDate = cal.getTime();

try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {

// 在7z中创建一个文件夹 SevenZArchiveEntry entry = outArchive.createArchiveEntry(dir, "foo/");

outArchive.putArchiveEntry(entry);

outArchive.closeArchiveEntry();

// 创建一个新的文件entry entry = new SevenZArchiveEntry();

// 文件命名 entry.setName("foo/bar");

// 文件创建时间、最后修改时间 entry.setCreationDate(creationDate);

entry.setAccessDate(accessDate);

outArchive.putArchiveEntry(entry);

// 这里是文件要写入的数据,可能是从其他文件中读取到的,也可以自己操作 byte[] data = XXX

outArchive.write(new byte[0]);

outArchive.closeArchiveEntry();

// 写入第二个文件,与第一个类似 entry = new SevenZArchiveEntry();

entry.setName("xyzzy");

outArchive.putArchiveEntry(entry);

outArchive.write(0);

outArchive.closeArchiveEntry();

// 完成7z文件写入后,需要调用finish outArchive.finish();

}

总结

以上就是Commons Compress处理7z格式的常用接口,同样的,如果使用中遇到了什么问题或bug,欢迎到Compress的JIRA上提问题,当然也是需要用英语提问的:)- ASF JIRA​issues.apache.org

 类似资料: