如何在ZipOutputStream中匹配已跳过字节的ZipEntry以续传压缩任务?
解决ZipEntry与已跳过字节的InputStream匹配问题
这个问题我之前处理过,核心矛盾在于:默认创建的ZipEntry会携带完整的原始数据元信息(比如未压缩大小),但你的InputStream已经跳过了前面的部分字节,直接用putNextEntry会导致压缩条目元数据和实际写入的数据流不匹配,最终解压时要么报错,要么得到不完整的文件。
下面是具体的解决步骤:
1. 确保准确跳过目标字节数
首先要注意:InputStream.skip()方法不一定能一次性跳过指定的所有字节(比如流提前结束、或者某些实现的限制),所以必须用循环确保跳过足够的字节:
long bytesToSkip = // 你需要跳过的字节数 long actualSkipped = 0; while (actualSkipped < bytesToSkip) { long skipped = inputStream.skip(bytesToSkip - actualSkipped); if (skipped == 0) { // 处理流提前结束的情况,比如抛出异常或终止流程 throw new IOException("无法跳过足够的字节,流提前结束"); } actualSkipped += skipped; }
2. 调整ZipEntry的元数据
创建ZipEntry时,必须手动设置它的未压缩大小为剩余要写入的数据量(原始总大小 - 实际跳过的字节数)。如果是文件源,你可以通过File.length()获取原始总大小;如果是其他流,你需要提前记录好原始总长度。
long originalTotalSize = // 原始数据流/文件的总大小 ZipEntry entry = new ZipEntry(object.getKey()); // 设置未压缩大小为剩余字节数 entry.setSize(originalTotalSize - actualSkipped); // 如果需要的话,还可以设置CRC校验值(如果提前计算了剩余数据的CRC) // entry.setCrc(remainingDataCrc); zipOutputStream.putNextEntry(entry);
3. 写入剩余数据流
最后将InputStream中剩余的字节写入ZipOutputStream即可:
byte[] buffer = new byte[8192]; // 用缓冲提高效率 int readLen; while ((readLen = inputStream.read(buffer)) != -1) { zipOutputStream.write(buffer, 0, readLen); } zipOutputStream.closeEntry();
特殊情况处理
如果无法提前获取原始总大小(比如数据流来自网络、动态生成),可以先将剩余数据读取到内存或临时文件中,计算出剩余数据的大小和CRC,再创建对应的ZipEntry并写入。当然这种方式会占用额外的存储资源,需要根据场景权衡。
内容的提问来源于stack exchange,提问作者1housand
相关产品推荐
相关产品推荐

