S3中Zip文件用ZipEntry获取未压缩大小返回-1的处理问询
解决S3中Zip文件用ZipInputStream获取未压缩大小返回-1的问题
我之前也碰到过一模一样的情况,ZipInputStream的entry.getSize()返回-1,大多是因为它属于流式读取类,要么是还没读到条目元数据里的大小字段,要么是部分不规范的Zip文件没正确存储这个值。下面给你几个实用的解决方案:
方法1:先把S3文件下载到本地临时文件,再用ZipFile处理
ZipFile确实能稳定获取条目未压缩大小,但它需要可随机访问的文件资源,没法直接传入S3路径。你可以先把Zip文件下载到本地临时文件,再用ZipFile解析:
import java.io.File; import java.io.IOException; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; public class S3ZipSizeHandler { public static void main(String[] args) throws IOException { String bucketName = "你的Bucket名称"; String zipObjectKey = "存储的Zip文件路径/比如test.zip"; // 创建临时文件,JVM退出时自动删除 File tempZip = File.createTempFile("s3-temp-zip-", ".zip"); tempZip.deleteOnExit(); // 从S3下载文件到临时文件 try (S3Client s3Client = S3Client.create()) { GetObjectRequest request = GetObjectRequest.builder() .bucket(bucketName) .key(zipObjectKey) .build(); s3Client.getObject(request, ResponseTransformer.toFile(tempZip)); } // 用ZipFile解析获取未压缩大小 try (ZipFile zipFile = new ZipFile(tempZip)) { Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); if (!entry.isDirectory()) { long uncompressedSize = entry.getSize(); System.out.printf("条目%s的未压缩大小:%d字节%n", entry.getName(), uncompressedSize); } } } } }
方法2:用Apache Commons Compress的ZipArchiveInputStream流式处理
如果你不想把整个文件下载到本地,可以用Apache Commons Compress库的ZipArchiveInputStream,它比JDK原生的ZipInputStream更可靠,能准确读取条目元数据:
先添加Maven依赖(如果用Gradle的话对应调整):
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version>1.24.0</version> <!-- 建议用最新稳定版 --> </dependency>
然后是代码示例:
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import java.io.IOException; import java.io.InputStream; public class S3ZipStreamSizeHandler { public static void main(String[] args) throws IOException { String bucketName = "你的Bucket名称"; String zipObjectKey = "存储的Zip文件路径/比如test.zip"; try (S3Client s3Client = S3Client.create()) { GetObjectRequest request = GetObjectRequest.builder() .bucket(bucketName) .key(zipObjectKey) .build(); // 直接获取S3对象输入流 try (InputStream s3Stream = s3Client.getObject(request); ZipArchiveInputStream zipStream = new ZipArchiveInputStream(s3Stream)) { ZipArchiveEntry entry; while ((entry = zipStream.getNextZipEntry()) != null) { if (!entry.isDirectory()) { long uncompressedSize = entry.getSize(); System.out.printf("条目%s的未压缩大小:%d字节%n", entry.getName(), uncompressedSize); } } } } } }
这个方法不用下载整个文件,直接流式处理,适合大Zip文件的场景。
方法3:手动解析Zip文件头部(进阶场景)
如果既不想依赖第三方库,又不想下载整个文件,可以手动读取Zip文件的末尾部分(中央目录区在Zip文件末尾)解析条目元数据。不过这个需要对Zip文件格式有了解,实现起来比较繁琐,容易出错,只适合对性能要求极高的场景,一般不推荐。
总结一下:优先推荐方法2,兼顾效率和可靠性;如果不能引入第三方库,就用方法1,逻辑简单不易出问题。
内容的提问来源于stack exchange,提问作者praveen
相关产品推荐
相关产品推荐

