Windows本地正常服务器部署报错:ZipException invalid distance too far back
问题:FTP获取Zip文件解析失败,报
java.util.zip.ZipException: invalid distance too far back 本地Windows环境运行正常,部署到服务器后抛出该错误,相关代码及报错信息如下:
业务代码
wrapper.connect(); byte[] archiveBytes = wrapper.retrieveFileBytes("some path"); try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(archiveBytes))) { ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { byte[] fileBytes = FileUtils.readZipEntry(zis); if (fileBytes.length == 0) { continue; } try (InputStream inputStream = new ByteArrayInputStream(fileBytes)) { var model = ftpFileReader.read(inputStream); domains.add(model); } } } return domains;
工具方法
public static byte[] readZipEntry(ZipInputStream zis) throws IOException { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { byte[] buffer = new byte[1024]; int count; while ((count = zis.read(buffer)) > -1) { outputStream.write(buffer, 0, count); } return outputStream.toByteArray(); } finally { zis.closeEntry(); } }
报错信息
java.util.zip.ZipException: invalid distance too far back
完整堆栈信息
org.springframework.retry.RetryException: Non-skippable exception in recoverer while processing; nested exception is java.util.zip.ZipException: invalid distance too far back at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$2.recover(FaultTolerantChunkProcessor.java:299) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:539) ~[spring-retry-1.3.3.jar!/:na] at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:387) ~[spring-retry-1.3.3.jar!/:na] at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:255) ~[spring-retry-1.3.3.jar!/:na] at org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:217) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.transform(FaultTolerantChunkProcessor.java:308) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:210) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:77) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:407) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:331) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-5.3.23.jar!/:5.3.23] at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:273) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:375) ~[spring-batch-infrastructure-4.3.7.jar!/:4.3.7] at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-4.3.7.jar!/:4.3.7] at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:145) ~[spring-batch-infrastructure-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:258) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:208) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:139) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149) ~[spring-batch-core-4.3.7.jar!/:4.3.7] at java.base/java.lang.Thread.run(Unknown Source) ~[na:na] Caused by: java.util.zip.ZipException: invalid distance too far back at java.base/java.util.zip.InflaterInputStream.read(Unknown Source) ~[na:na] at java.base/java.util.zip.ZipInputStream.read(Unknown Source) ~[na:na] at java.base/java.util.zip.ZipInputStream.closeEntry(Unknown Source) ~[na:na] at ftp.utils.FileUtils.readZipEntry(FileUtils.java:18)
排查思路与解决方案
错误本质
该错误是Zip文件损坏导致的解压失败,本地正常但服务器异常,核心原因是FTP传输模式不匹配:Windows默认用ASCII模式传输,若服务器仍用ASCII模式传输二进制Zip文件,会篡改字节(比如转换换行符、截断特殊字节),最终破坏Zip文件结构。
解决方案
强制FTP使用二进制模式传输
在获取文件前设置传输模式为二进制,以Apache Commons Net的FTPClient为例:wrapper.connect(); // 新增:设置二进制传输模式,避免字节篡改 wrapper.setFileType(FTP.BINARY_FILE_TYPE); byte[] archiveBytes = wrapper.retrieveFileBytes("some path");验证文件完整性
- 在服务器上把下载的
archiveBytes保存为本地文件,用unzip命令尝试解压,确认是否损坏; - 对比本地和服务器下载文件的MD5值,不一致则说明传输过程中字节被篡改。
- 在服务器上把下载的
修正工具方法的异常处理
当前readZipEntry的finally块调用closeEntry()时,若之前读取流已抛出异常,closeEntry()会继续读取流导致二次错误,建议增加异常捕获:public static byte[] readZipEntry(ZipInputStream zis) throws IOException { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { byte[] buffer = new byte[4096]; // 增大缓冲区提升效率 int count; while ((count = zis.read(buffer)) != -1) { outputStream.write(buffer, 0, count); } return outputStream.toByteArray(); } finally { try { zis.closeEntry(); } catch (IOException e) { // 记录日志,避免closeEntry的异常覆盖原读取异常 e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者user19282140
相关产品推荐
相关产品推荐

