All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dromara.hutool.extra.compress.archiver.StreamArchiver Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2023 looly([email protected])
 * Hutool is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package org.dromara.hutool.extra.compress.archiver;

import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.extra.compress.CompressException;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.function.Predicate;

/**
 * 数据归档封装,归档即将几个文件或目录打成一个压缩包
* 支持的归档文件格式为: *
    *
  • {@link ArchiveStreamFactory#AR}
  • *
  • {@link ArchiveStreamFactory#CPIO}
  • *
  • {@link ArchiveStreamFactory#JAR}
  • *
  • {@link ArchiveStreamFactory#TAR}
  • *
  • {@link ArchiveStreamFactory#ZIP}
  • *
* * @author looly */ public class StreamArchiver implements Archiver { /** * 创建归档器 * * @param charset 编码 * @param archiverName 归档类型名称,见{@link ArchiveStreamFactory} * @param file 归档输出的文件 * @return StreamArchiver */ public static StreamArchiver of(final Charset charset, final String archiverName, final File file) { return new StreamArchiver(charset, archiverName, file); } /** * 创建归档器 * * @param charset 编码 * @param archiverName 归档类型名称,见{@link ArchiveStreamFactory} * @param out 归档输出的流 * @return StreamArchiver */ public static StreamArchiver of(final Charset charset, final String archiverName, final OutputStream out) { return new StreamArchiver(charset, archiverName, out); } private final ArchiveOutputStream out; /** * 构造 * * @param charset 编码 * @param archiverName 归档类型名称,见{@link ArchiveStreamFactory} * @param file 归档输出的文件 */ public StreamArchiver(final Charset charset, final String archiverName, final File file) { this(charset, archiverName, FileUtil.getOutputStream(file)); } /** * 构造 * * @param charset 编码 * @param archiverName 归档类型名称,见{@link ArchiveStreamFactory} * @param targetStream 归档输出的流 */ public StreamArchiver(final Charset charset, final String archiverName, final OutputStream targetStream) { if("tgz".equalsIgnoreCase(archiverName) || "tar.gz".equalsIgnoreCase(archiverName)){ //issue#I5J33E,支持tgz格式解压 try { this.out = new TarArchiveOutputStream(new GzipCompressorOutputStream(targetStream)); } catch (IOException e) { throw new IORuntimeException(e); } return; } final ArchiveStreamFactory factory = new ArchiveStreamFactory(charset.name()); try { this.out = factory.createArchiveOutputStream(archiverName, targetStream); } catch (final ArchiveException e) { throw new CompressException(e); } //特殊设置 if (this.out instanceof TarArchiveOutputStream) { ((TarArchiveOutputStream) out).setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); } else if (this.out instanceof ArArchiveOutputStream) { ((ArArchiveOutputStream) out).setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD); } } /** * 将文件或目录加入归档包,目录采取递归读取方式按照层级加入 * * @param file 文件或目录 * @param path 文件或目录的初始路径,null表示位于根路径 * @param predicate 文件过滤器,指定哪些文件或目录可以加入,当{@link Predicate#test(Object)}为{@code true}加入,null表示全部加入 * @return this * @throws IORuntimeException IO异常 */ @Override public StreamArchiver add(final File file, final String path, final Predicate predicate) throws IORuntimeException { try { addInternal(file, path, predicate); } catch (final IOException e) { throw new IORuntimeException(e); } return this; } /** * 结束已经增加的文件归档,此方法不会关闭归档流,可以继续添加文件 * * @return this */ @Override public StreamArchiver finish() { try { this.out.finish(); } catch (final IOException e) { throw new IORuntimeException(e); } return this; } @Override public void close() { try { finish(); } catch (final Exception ignore) { //ignore } IoUtil.closeQuietly(this.out); } /** * 将文件或目录加入归档包,目录采取递归读取方式按照层级加入 * * @param file 文件或目录 * @param path 文件或目录的初始路径,{@code null}表示位于根路径 * @param predicate 文件过滤器,指定哪些文件或目录可以加入,当{@link Predicate#test(Object)}为{@code true}加入。 */ private void addInternal(final File file, final String path, final Predicate predicate) throws IOException { if (null != predicate && !predicate.test(file)) { return; } final ArchiveOutputStream out = this.out; final String entryName; if (StrUtil.isNotEmpty(path)) { // 非空拼接路径,格式为:path/name entryName = StrUtil.addSuffixIfNot(path, StrUtil.SLASH) + file.getName(); } else { // 路径空直接使用文件名或目录名 entryName = file.getName(); } out.putArchiveEntry(out.createArchiveEntry(file, entryName)); if (file.isDirectory()) { // 目录遍历写入 final File[] files = file.listFiles(); if (ArrayUtil.isNotEmpty(files)) { for (final File childFile : files) { addInternal(childFile, entryName, predicate); } } } else { if (file.isFile()) { // 文件直接写入 FileUtil.writeToStream(file, out); } out.closeArchiveEntry(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy