同一Zip条目写入多数据后ByteArrayOutputStream大小未更新的问题
问题原因
ZipOutputStream内部自带缓冲区,写入的数据会先暂存到缓冲区中,不会立即同步到下层的ByteArrayOutputStream,这就是你看到outputStream.size()一直保持初始值的原因。另外,closeEntry()会终止当前Zip条目,之后无法再向同一个条目写入数据,这和你需要持续追加内容到abc.csv的需求冲突。
解决方案
- 实时刷新缓冲区:每次向
ZipOutputStream写入数据后,调用flush()方法,将缓冲区的数据同步到ByteArrayOutputStream,这样就能正确获取已写入的字节大小。 - 优化资源管理:使用try-with-resources自动关闭流,避免手动关闭导致的资源泄漏。
- 调整流生命周期:确保
ZipOutputStream在整个写入过程中保持打开状态,仅在所有数据处理完成后再关闭条目和流。
修改后的代码
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream); private void addToS3(List<Data> data) throws IOException { try { zipOutputStream.putNextEntry(new ZipEntry("abc.csv")); for (Data item : data) { // 使用try-with-resources自动管理流资源 try (InputStream inputStream = new ByteArrayInputStream(item.getBytes()); InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader bufferedReader = new BufferedReader(reader)) { StringBuilder csvContent = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { csvContent.append(line).append("\n"); } // 写入数据后立即刷新缓冲区,同步到ByteArrayOutputStream zipOutputStream.write(csvContent.toString().getBytes(StandardCharsets.UTF_8)); zipOutputStream.flush(); // 检查当前已写入的字节大小,达到阈值则分片上传 if (outputStream.size() > 5 * 1024 * 1024) { uploadToS3ByPart(new ByteArrayInputStream(outputStream.toByteArray()), false); outputStream.reset(); } } } zipOutputStream.closeEntry(); } finally { zipOutputStream.close(); } // 上传剩余的最后一部分数据 uploadToS3ByPart(new ByteArrayInputStream(outputStream.toByteArray()), true); }
补充说明
- 调用
flush()只会将缓冲区的数据同步到下层流,不会终止当前Zip条目,因此可以继续向同一个abc.csv条目追加内容。 - 分片上传时,
outputStream.reset()会清空当前的字节数组,后续写入的数据会继续作为同一个Zip条目的内容,最终所有分片拼接后会形成完整的Zip文件,包含完整的abc.csv条目。 - try-with-resources会自动关闭所有实现了
AutoCloseable的资源,无需手动调用close(),避免了因忘记关闭流导致的资源泄漏问题。
内容的提问来源于stack exchange,提问作者Chandana MB
相关产品推荐
相关产品推荐

