Java不解压读取Zip文件失败:write字节数为0的原因咨询
问题描述
不少开发者推荐用zip.getInputStream(entry)不解压直接读取Zip内文件,但我多次尝试都失败了——fileOutputStream.write(bytes)写入字节数为0,只有先解压才能拿到真实内容。测试代码如下:
private static final String ZIP_FILE_PATH = "F:/zip-test/test.zip"; private static final String DECOMPRESS_PATH_SUFFIX = "F:/zip-decompress"; @Test public void readZipInnerFileContent() throws IOException { ZipFile zipFile = new ZipFile(ZIP_FILE_PATH); Enumeration<? extends ZipEntry> entries = zipFile.entries(); Map<String, InputStream> map = MapUtil.newHashMap(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); String name = zipEntry.getName(); if (zipEntry.isDirectory()) { File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name); file.mkdirs(); continue; } InputStream inputStream = zipFile.getInputStream(zipEntry); map.put(name, inputStream); } map.forEach((k, v) -> { File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + k); try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { byte[] bytes = new byte[v.available()]; fileOutputStream.write(bytes); fileOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } }); log.info("read end"); }
问题原因
核心问题出在错误使用InputStream.available()方法:
available()返回的是当前输入流中无需阻塞就能读取的字节数,对于Zip压缩流来说,这个值并不是文件的总大小,初始状态下甚至可能返回0。用这个值创建字节数组,本质是生成了一个长度为0的空数组,写入自然不会有内容。- 另外,将所有
InputStream先存入Map再统一处理的方式存在隐患:ZipFile的输入流依赖于自身实例的存活,后续操作可能导致流状态异常,但这不是本次写入0字节的直接原因。
修复后的代码
修改读取写入逻辑,用循环读取缓冲区的方式处理流:
private static final String ZIP_FILE_PATH = "F:/zip-test/test.zip"; private static final String DECOMPRESS_PATH_SUFFIX = "F:/zip-decompress"; @Test public void readZipInnerFileContent() throws IOException { // 用try-with-resources自动管理ZipFile生命周期 try (ZipFile zipFile = new ZipFile(ZIP_FILE_PATH)) { Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); String name = zipEntry.getName(); if (zipEntry.isDirectory()) { File file = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name); file.mkdirs(); continue; } File outputFile = new File(DECOMPRESS_PATH_SUFFIX + File.separator + name); // 确保父目录存在,避免写入失败 if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } // 自动关闭输入输出流 try (InputStream inputStream = zipFile.getInputStream(zipEntry); FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) { byte[] buffer = new byte[4096]; // 4KB缓冲区,可根据需求调整 int readLen; // 循环读取直到流结束 while ((readLen = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, readLen); } fileOutputStream.flush(); } } } log.info("read end"); }
关键修改点
- 用try-with-resources自动管理
ZipFile、InputStream和FileOutputStream的生命周期,避免资源泄漏。 - 放弃使用
available(),改用固定大小缓冲区循环读取,直到read()返回-1,表示流读取完毕。 - 读取文件时直接处理写入,不再将
InputStream存入Map,避免流状态异常。
内容的提问来源于stack exchange,提问作者Chris Li
相关产品推荐
相关产品推荐

