You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从S3获取的Zip/tar.gz文件流中仅列出所有文件名?

基于S3部分下载提取Zip文件文件名的方案

针对你的需求,完全可以利用S3的范围请求(Range)结合Zip格式的特性,只下载包含元信息的关键区域,就能提取所有文件的相对路径,无需下载完整压缩包,大幅节省带宽。

核心原理

Zip格式的文件元数据(包括文件名)集中存储在中央目录(Central Directory),而中央目录的位置由文件尾部的**EOCD(End of Central Directory Record)**标记指定。通过两次范围请求:先读取文件尾部找到EOCD,再读取完整的中央目录,就能解析出所有文件名。

具体步骤

  • 第一步:获取文件总大小
    调用S3的headObject接口获取文件的Content-Length,这一步仅获取元数据,不下载任何文件内容。
  • 第二步:读取文件尾部找EOCD
    EOCD通常位于文件最后几百字节内,发起范围请求获取最后1024字节(可根据实际情况调整),解析出中央目录的起始偏移和大小。
  • 第三步:读取中央目录并解析文件名
    根据上一步得到的偏移和大小,发起范围请求下载中央目录区域,解析该区域即可提取所有Zip条目的文件名。

推荐工具库

  • Apache Commons Compress:提供了成熟的Zip格式解析工具,比如CentralDirectoryParser可以直接解析EOCD和中央目录,无需手动处理底层字节逻辑。
  • Apache Commons IO:简化流与字节数组的转换操作,避免手动处理流关闭等繁琐工作。

代码示例

import org.apache.commons.compress.archivers.zip.CentralDirectory;
import org.apache.commons.compress.archivers.zip.CentralDirectoryParser;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.io.IOUtils;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;

import java.io.ByteArrayInputStream;
import java.io.IOException;

public class S3ZipFilenameExtractor {
    public static void extractFilenames(S3Client s3Client, String bucket, String key) throws IOException {
        // 1. 获取文件总大小
        HeadObjectResponse headResp = s3Client.headObject(HeadObjectRequest.builder()
                .bucket(bucket)
                .key(key)
                .build());
        long totalFileSize = headResp.contentLength();

        // 2. 请求文件尾部1024字节,解析EOCD
        long tailStart = Math.max(0, totalFileSize - 1024);
        GetObjectRequest tailReq = GetObjectRequest.builder()
                .bucket(bucket)
                .key(key)
                .range(String.format("bytes=%d-%d", tailStart, totalFileSize - 1))
                .build();
        ResponseInputStream<?> tailStream = s3Client.getObject(tailReq);
        byte[] tailBytes = IOUtils.toByteArray(tailStream);

        CentralDirectoryParser parser = new CentralDirectoryParser();
        parser.parse(tailBytes, 0, tailBytes.length);
        CentralDirectory centralDir = parser.getCentralDirectory();
        long cdStartOffset = centralDir.getStartOfCentralDirectory();
        long cdTotalSize = centralDir.getSizeOfCentralDirectory();

        // 3. 请求中央目录区域,解析文件名
        GetObjectRequest cdReq = GetObjectRequest.builder()
                .bucket(bucket)
                .key(key)
                .range(String.format("bytes=%d-%d", cdStartOffset, cdStartOffset + cdTotalSize - 1))
                .build();
        ResponseInputStream<?> cdStream = s3Client.getObject(cdReq);
        byte[] cdBytes = IOUtils.toByteArray(cdStream);

        try (ZipArchiveInputStream zipIn = new ZipArchiveInputStream(new ByteArrayInputStream(cdBytes))) {
            ZipArchiveEntry entry;
            while ((entry = zipIn.getNextZipEntry()) != null) {
                if (!entry.isDirectory()) {
                    String filename = entry.getName();
                    // 这里处理文件名逻辑
                    System.out.println(filename);
                }
            }
        }
    }
}

注意事项

  • 该方案仅适用于标准Zip格式,分卷压缩、加密压缩等特殊格式可能无法正常解析。
  • 如果文件尾部的1024字节不足以包含EOCD,可以适当扩大请求的尾部长度,或者循环递增长度直到找到EOCD标记。
  • 确保使用的S3客户端支持范围请求,AWS SDK默认支持该功能。

内容的提问来源于stack exchange,提问作者沈小虎

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:41:15