Apache Commons Compress
简介
Apache Commons Copress是 Apache Commons系列工具的一个部分
是一个提供了更丰富的压缩功能和支持更多压缩格式的工具包
前面我们可知 Java自带对zip,gzip,jar格式的压缩文件支持
如果我们要处理7z,tar,bzip等格式
或者使用LZ4,Snappy等其他压缩算法
就可以使用 Apache Compress
因为rar压缩算法不公开 所以Apache Compress未提供支持
使用
压缩流工厂
压缩流工厂是最基础的压缩流创建工具 用于创建一个输入/输出流进行压缩/解压缩
- 创建一个压缩输出流
第一参数是CompressorStreamFactory.GZIP 所以是GZIP压缩流
如果指定为其他格式 则为其他格式压缩流
CompressorOutputStream gzippedOut = new CompressorStreamFactory()
.createCompressorOutputStream(CompressorStreamFactory.GZIP, myOutputStream);
- 创建一个解压缩输入流
CompressorInputStream input = new CompressorStreamFactory()
.createCompressorInputStream(originalInput);
- 创建一个文档输入流
ArchiveInputStream input = new ArchiveStreamFactory()
.createArchiveInputStream(originalInput);
文档输入流ArchiveInputStream和解压缩输入流 CompressorInputStream的区别是
ArchiveInputStream是文档输入流 用于处理归档格式文件 用于处理ZIP,JAR,AR,CPIO,ARJ,7Z,TAR
等归档型包文件
CompressorInputStream是解压缩输入流 用于处理BZIP2,GZIP,PACK200,SNAPPY_FRAMED,
Z,DEFLATE,XZ,LZMA,LZ4_FRAMED,ZSTANDARD压缩型包文件
流 | 处理文件 | 格式 |
---|---|---|
ArchiveInputStream | 归档型包 | ZIP,JAR,AR,CPIO,ARJ,7Z,TAR…… |
CompressorInputStream | 压缩型包 | BZIP2,GZIP,PACK200,SNAPPY_FRAMED…… |
解压缩文件 通用流程
- 核心就是ArchiveInputStream 类
ArchiveInputStream input = new ArchiveStreamFactory()
.createArchiveInputStream(new BufferedInputStream(new FileInputStream("F:/zipoutput.zip")));
构建的ArchiveInputStream 必须使用支持mark标记的流作为底层流 否则会抛出不支持标记异常
所以这里使用了BufferedInputStream 包装FileInputStream
File targetDir = new File("F:\\uncompress");
此处使用了try with resource(Java 7特性) 可以自动关闭流
try (ArchiveInputStream i = input) {
ArchiveEntry entry = null;
while ((entry = i.getNextEntry()) != null) {
if (!i.canReadEntryData(entry)) {
不能读取 或不支持的格式 算法 跳过此文件
continue;
}
文件名 用于下面文件File类型的参数 所以需要设定全路径
此处为F:\uncompress\+文件名
String name = targetDir + File.separator + entry.getName();
File f = new File(name);
if (entry.isDirectory()) {
if (!f.isDirectory() && !f.mkdirs()) {
throw new IOException
("failed to create directory " + f);
}
} else {
File parent = f.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException
("failed to create directory " + parent);
}
输出到目标文件 此处调用的是Java NIO
的Files工具类的ewOutputStream方法
try (OutputStream o = Files.newOutputStream(f.toPath())) {
IOUtils.copy(i, o);
}
}
}
}
- 从一个压缩型文件包解压
// 此处使用了NIO的文件输入流创建方式 因为NIO流是不支持标记和重置的
所以又使用了BufferedInputStream包装文件输入流
输入的文件格式是已知的tar.gz型 所以直接指定GzipCompressorInputStream为处理流
gzip处理流上又套接一层TarArchiveInputStream处理解压后的tar归档包文件
try (InputStream fi = new Files.newInputStream(Paths.get("my.tar.gz"));
InputStream bi = new BufferedInputStream(fi);
InputStream gzi = new GzipCompressorInputStream(bi);
ArchiveInputStream o = new TarArchiveInputStream(gzi)) {
}
打包文件 通用流程
- 核心是ArchiveOutputStream 类似JDK中提供的ZipOutputStream
与归档文件输入流不同 ArchiveOutputStream不支持7z压缩格式,此工具提供了SevenZOutputFile类专用于处理7z格式文件压缩
需要打包的文件
Collection<File> filesToArchive = Arrays.asList(new File("E:\\图片\\截图").listFiles());
createArchiveOutputStream()方法的第一个形参指定压缩文件格式 此处设定为tar格式
ArchiveOutputStream outputStream=new ArchiveStreamFactory()
.createArchiveOutputStream(ArchiveStreamFactory.TAR
,new FileOutputStream("F:\\zipArchiveoutput.tar"));
try (ArchiveOutputStream o = outputStream) {
for (File f : filesToArchive) {
ArchiveEntry entry = o.createArchiveEntry(f, f.getName());
o.putArchiveEntry(entry);
if (f.isFile()) {
try (InputStream i = Files.newInputStream(f.toPath())) {
使用IOUtils工具方法进行写入
IOUtils.copy(i, o);
}
}
每写入完一个实体 必须关闭这个实体
o.closeArchiveEntry();
}
压缩完毕
此处和JDK的ZipOutputStream的finsh()方法不一样
ZipOutputStream是自动关闭所有未关闭实体的
而Apache compress必须手动关闭实体
outputStream.finish();
}
7z文件
压缩和解压缩7z文件 必须要手动添加依赖 ## XZ For Java
Apache compress反正是没有引用这个依赖包
官方文档只提示了使用一些特殊算法是需要引入此依赖
但实际上压缩7z文件必须引入依赖 如果不手动引入就会抛出未找到类异常
Gradle引入
compile group: 'org.tukaani', name: 'xz', version: '1.8'
- 打包7z文件
代码上大同小异
Collection<File> filesTo7z = Arrays.asList(new File("E:\\图片\\B站截图").listFiles());
try (SevenZOutputFile sevenZOutputFile = new SevenZOutputFile
(new File("F:\\7zoutput."+ArchiveStreamFactory.SEVEN_Z))) {
设置压缩算法 默认是LZMA2 通常用默认的即可
sevenZOutputFile.setContentCompression(SevenZMethod.LZMA2);
for (File file : filesTo7z) {
创建压缩实体
SevenZArchiveEntry entry = sevenZOutputFile
.createArchiveEntry(file, file.getName());
放入压缩文件 和其他几种压缩流基本一致的操作
sevenZOutputFile.putArchiveEntry(entry);
try (FileInputStream fis = new FileInputStream(file)) {
byte[] bytes=new byte[4096];
int len=-1;
while ((len = fis.read(bytes)) != -1) {
sevenZOutputFile.write(bytes,0,len);
}
}
sevenZOutputFile.closeArchiveEntry();
}
}
- 解压缩7z文件
从文件解压
SevenZFile sevenZFile = new SevenZFile(new File("F:\\7zoutput.7z"));
for (SevenZArchiveEntry entry : sevenZFile.getEntries()) {
try (FileOutputStream fous = new FileOutputStream("F:\\uncompress\\" + entry.getName())) {
每次要读入文件时 必须调用getNextEntry()方法
此时才会真正的打开输入流 否则会直接抛出越界异常
sevenZFile.getNextEntry();
byte[] content = new byte[4096];
int len=-1;
while ((len = sevenZFile.read(content)) != -1) {
fous.write(content,0,len);
}
}
}
sevenZFile.close();
从内存解压
byte[] inputData=new byte[]{}; 文件在内存中的数据
输入NIO的内存通道
SeekableInMemoryByteChannel inMemoryByteChannel = new SeekableInMemoryByteChannel(inputData);
构造SevenZFile
SevenZFile sevenZFile = new SevenZFile(inMemoryByteChannel);
SevenZArchiveEntry entry = sevenZFile.getNextEntry();
读取
sevenZFile.read();
解压7加密文件
此构造方法的第二个参数为加密密码 此处输入密码为“secret”
SevenZFile sevenZFile = new SevenZFile(new File("archive.7z"), "secret"..toCharArray());
解压过程和未加密文件无区别
for (SevenZArchiveEntry entry : sevenZFile.getEntries()) {
try (FileOutputStream fous = new FileOutputStream("F:\\uncompress\\" + entry.getName())) {
每次要读入文件时 必须调用getNextEntry()方法
此时才会真正的打开输入流 否则会直接抛出越界异常
sevenZFile.getNextEntry();
byte[] content = new byte[4096];
int len=-1;
while ((len = sevenZFile.read(content)) != -1) {
fous.write(content,0,len);
}
}
}
LZ4压缩
LZ4是压缩速度和压缩效率都比较高的一种压缩文件算法
- 压缩
InputStream in = Files.newInputStream(Paths.get("F:\\zipArchiveoutput.tar"));
OutputStream fout = Files.newOutputStream(Paths.get("F:\\zipArchiveoutput.tar.lz4"));
BufferedOutputStream out = new BufferedOutputStream(fout);
FramedLZ4CompressorOutputStream lzOut = new FramedLZ4CompressorOutputStream(out);
IOUtils.copy(in,lzOut);
lzOut.close();
in.close();
- 解压缩
InputStream fin = Files.newInputStream(Paths.get("F:\\zipArchiveoutput.tar.lz4"));
BufferedInputStream in = new BufferedInputStream(fin);
OutputStream out = Files.newOutputStream(Paths.get("F:\\archive.tar"));
FramedLZ4CompressorInputStream zIn = new FramedLZ4CompressorInputStream(in);
IOUtils.copy(zIn,out);
out.close();
zIn.close();