栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java不解压压缩包的前提下,解析压缩包内容

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java不解压压缩包的前提下,解析压缩包内容

近期工作过程中,遇到了一个需要解析压缩包的功能开发。对于这个功能,如果频繁的解压压缩包,在性能上多少有些损耗,且解压文件,会产生大量中间文件,不适合后续管理。特别是现在都是基于容器化部署,如果文件操作处理不当,导致删除失败,将很快打满容器磁盘容量,引起容器崩溃重启。

综合考虑之后,采用ArchiveInputStream,在不解压文件的前提下,解析压缩包。
具体实践如下。

整体流程
  1. 从SFTP获取压缩包
  2. 读取压缩包文件内容
  3. 删除本地压缩包文件
从SFTP获取压缩包文件

添加项目依赖,使用jcraft包来连接SFTP服务器。


  com.jcraft
    jsch
    0.1.54

引入依赖后,需要实现一个工具类来连接SFTP。此处只列出关键代码,如果详细工具类,可以网上找一下,有很多。

public class SFTPUtil {

    
    public void connect() {
        try {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            sshSession = jsch.getSession(username, host, port);
            if (log.isInfoEnabled()) {
                log.info("Session created.");
            }
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            if (log.isInfoEnabled()) {
                log.info("Session connected.");
            }
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            if (log.isInfoEnabled()) {
                log.info("Opening Channel.");
            }
            sftp = (ChannelSftp) channel;
            if (log.isInfoEnabled()) {
                log.info("Connected to " + host + ".");
            }
        }
        catch (Exception e) {
            log.error("Connected to " + host + "failed.", e);
        }
    }

    
    public void disconnect() {
        if (this.sftp != null) {
            if (this.sftp.isConnected()) {
                this.sftp.disconnect();
                if (log.isInfoEnabled()) {
                    log.info("sftp is closed already");
                }
            }
        }
        if (this.sshSession != null) {
            if (this.sshSession.isConnected()) {
                this.sshSession.disconnect();
                if (log.isInfoEnabled()) {
                    log.info("sshSession is closed already");
                }
            }
        }
    }

	
    public boolean downloadFile(String remotePath, String remoteFileName, String localPath, String localFileName) {
        FileOutputStream fieloutput = null;
        if (!remotePath.endsWith("/")) {
            remotePath += "/";
        }
        if (!localPath.endsWith("/")) {
            localPath += "/";
        }
        String remoteFilePath = remotePath + remoteFileName;
        try {
            String filePath = localPath + localFileName;
            SftpATTRS attrs = sftp.lstat(remoteFilePath);
            if (attrs.isFifo()){

            }
            // sftp.cd(remotePath);
            mkdirs(localPath);
            File file = new File(filePath);
            fieloutput = new FileOutputStream(file);
            sftp.get(remoteFilePath, fieloutput);
            if (log.isInfoEnabled()) {
                log.info("===DownloadFile:" + remoteFileName + " success from sftp.");
            }
            return true;
        } catch (FileNotFoundException e) {
            log.warn("file not exists ,file name is " + remoteFilePath);
        } catch ( SftpException | baseAppException e){
            log.error("download file failed.file name is " + remoteFilePath, e);
        } finally {
            if (null != fieloutput) {
                try {
                    fieloutput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
}
从压缩包中获取文件

核心的代码就是下面这段

public final class TarFileUtil {
	
	public static byte[] getBytesFromTarFile(File tarFile, String targetFilePath, String targetFileName) {
        ArchiveInputStream archiveInputStream = null;
        try {
            archiveInputStream = getArchiveInputStream(tarFile);
            TarArchiveEntry entry = null;
            while ((entry = (TarArchiveEntry) archiveInputStream.getNextEntry()) != null) {
                if (entry.getSize() <= 0) {
                    continue;
                }
                if (!StringUtils.isEmpty(targetFilePath) && !entry.getName().startsWith(targetFilePath)) {
                    continue;
                }
                if (!StringUtils.isEmpty(targetFileName) && !entry.getName().endsWith(targetFileName)) {
                    continue;
                }
                return FileUtil.getContent(archiveInputStream);
            }

        } catch (Exception e) {
            LOGGER.error("获取压缩包文件失败!", e);
        } finally {
            if (null != archiveInputStream) {
                try {
                    archiveInputStream.close();
                } catch (IOException e) {
                    LOGGER.error("file close error!", e);
                }
            }
        }

        return null;
    }
    private static ArchiveInputStream getArchiveInputStream(File tarFile) throws IOException, ArchiveException {
        if (StringUtils.endsWithIgnoreCase(tarFile.getName(), ".gz")) {
            return new ArchiveStreamFactory()
                    .createArchiveInputStream("tar", new GZIPInputStream(new BufferedInputStream(new FileInputStream(tarFile))));
        } else {
            return new ArchiveStreamFactory()
                    .createArchiveInputStream("tar", new BufferedInputStream(new FileInputStream(tarFile)));
        }
    }
}

通过个方法还可以做一些文件操作的其他方法实现。比如我在工具类中加入了

// 将目标文件的内容转化为String,并返回
public static String readTarFileToStr(File tarFile, String targetFilePath, String targetFileName);

// 将目标文件内容读取出来,写入到本地文件,并返回
public static File readTarFileToFile(File tarFile, String targetFilePath, String targetFileName);

// 列举指定目录下,匹配上文件名的所有文件列表
public static List listFilesInPath(File tarFile, String targetFilePath, String targetFileName);

// 将文件按行读出,并返回内容列表
public static List getLinesFromTarFile(File tarFile, String targetFilePath, String targetFileName);

你也可以根据自己的需要,新增其他方法。因为这些方法实现逻辑类似,此处不再赘述。

注意:ArchiveInputStream的读取和关闭,应保证在一个方法体里,尽量不要将ArchiveInputStream对象作为结果返回出去,在外层做关闭操作,以免文件流关闭失败,导致临时文件无法删除。

删除临时文件

压缩包解析完成后,切记删除下载的压缩包。删除前,确认所有的文件流都关闭了。

public class ResolveHandel{

	public void resolveTarFileMethod() {
		
		try{
			sftpUtil.connect();
			sftpUtil.downloadFile(filePath + fileName);
			
			// do something to resolve package
			
		} catch (Exception e){
			// deal with exception
		} finally {
			// 删除本地缓存文件
            sftpUtil.deleteFile(filePath + fileName);

            // 断开连接
            sftpUtil.disconnect();
		}
	}

}

此处指列出了关键代码,如有不明白的地方,可以留言交流。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351244.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号