如何在Java中创建保留目录结构的.tar.gz文件
修复.tar.gz打包时目录结构扁平化问题
你的代码核心逻辑方向正确,通过以下调整可确保目录结构被完整保留:
关键修改点
- 添加长文件名支持:避免路径过长导致目录结构被截断
- 优化流管理:用try-with-resources自动管理流,规避资源泄漏和关闭顺序错误
- 明确文件属性设置:保留原文件的修改时间,保证tar包属性准确性
修改后的完整代码
public void exportStaticFilesTar(String appID) throws Exception { String filename = "ParentDir.tar.gz"; // 替换为实际的ParentDir路径 String path = "<path to ParentDir>"; // 使用try-with-resources自动管理所有输出流 try (FileOutputStream fOut = new FileOutputStream(new File(filename)); BufferedOutputStream bOut = new BufferedOutputStream(fOut); GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(bOut); TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) { // 启用长文件名支持,避免路径过长问题 tOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); addFileToTarGz(tOut, path, ""); } catch (Exception e) { log.error("Error creating .tar.gz: " + e); throw e; // 重新抛出异常,让调用者感知错误 } // 后续下载逻辑 } private void addFileToTarGz(TarArchiveOutputStream tOut, String path, String base) throws IOException { File f = new File(path); // 构建完整的entry路径,确保层级正确 String entryName = base + f.getName(); TarArchiveEntry tarEntry = new TarArchiveEntry(f, entryName); // 设置文件修改时间,保持原文件属性 tarEntry.setModTime(new Date(f.lastModified())); tOut.putArchiveEntry(tarEntry); if (f.isFile()) { // 使用try-with-resources自动关闭输入流 try (FileInputStream in = new FileInputStream(f)) { IOUtils.copy(in, tOut); } tOut.closeArchiveEntry(); } else { tOut.closeArchiveEntry(); File[] children = f.listFiles(); if (children != null) { for (File child : children) { // 递归时传递当前目录的完整路径作为下一级的base addFileToTarGz(tOut, child.getAbsolutePath(), entryName + "/"); } } } }
额外注意事项
- 确保
path变量指向ParentDir目录本身,而非它的父目录或子目录 - 确认ParentDir及其子目录、文件拥有足够读取权限,避免
listFiles()返回null - 建议使用最新稳定版的Commons Compress依赖,规避旧版本的已知bug
内容的提问来源于stack exchange,提问作者user1971376
相关产品推荐
相关产品推荐

