如何解决Java读取含空目录的ZipInputStream时的ZipException异常
解决Java ZipInputStream读取Zip时的「Invalid Block lengths」异常
问题根源
Java自带的ZipInputStream对Zip格式的校验比较严格,当压缩包中包含名为.的根目录条目(属于非标准Zip结构)时,读取后续条目会触发格式校验失败,抛出ZipException。而Windows压缩工具对这类非标准结构的兼容性更强,所以能正常解压。
可行解决方案
方案一:跳过特殊目录条目,修正流位置
如果不想引入第三方库,可以手动跳过.目录对应的流数据块,避免后续流位置错乱:
try { ZipEntry ze = null; while ((ze = zin.getNextEntry()) != null) { // 跳过名为"."的特殊目录条目 if (".".equals(ze.getName())) { // 消耗当前条目对应的流数据(即使是目录,也需要跳过空数据块) byte[] buffer = new byte[1024]; while (zin.read(buffer) != -1) { // 仅消耗流,无业务操作 } zin.closeEntry(); continue; } if (!ze.isDirectory()) { // 这里处理文件条目逻辑 } zin.closeEntry(); } } catch (ZipException ex) { // 异常处理逻辑 } finally { zin.close(); }
方案二:用Apache Commons Compress替代JDK实现
Apache Commons Compress对非标准Zip格式的兼容性更好,能自动处理这类特殊条目,无需手动操作:
- 先引入Maven依赖:
<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; // ... try (ZipArchiveInputStream zais = new ZipArchiveInputStream(zin)) { ZipArchiveEntry zae = null; while ((zae = zais.getNextZipEntry()) != null) { if (!zae.isDirectory()) { // 处理文件条目逻辑 } } } catch (IOException ex) { // 异常处理逻辑 }
该库支持直接从输入流读取,不需要将文件落地到本地文件系统,完全符合你的需求。
内容的提问来源于stack exchange,提问作者barduchi
相关产品推荐
相关产品推荐

