You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mac下载后生成的Zip文件始终损坏问题排查求助

问题:Mac无法解压生成的Zip文件,提示格式不支持

将一组对象打包为Zip文件,已实现如下Zip转换类和Spring控制器,但在Mac上下载生成的Zip文件后,始终无法解压,系统提示“Unable to expand filename.zip. It is in an unsupported format.”。尝试调整流的关闭方式、修改ContentType等操作均无效,恳请帮忙排查问题所在。

Zip转换类代码

public class ZipFile {
    public byte[] createZipByteArray(String fileName, byte[] content) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try (byteArrayOutputStream; ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
            zipOutputStream.setLevel(Deflater.NO_COMPRESSION);
            ZipEntry zipEntry = new ZipEntry(fileName);
            zipOutputStream.putNextEntry(zipEntry);
            zipOutputStream.write(content);
            zipOutputStream.closeEntry();
            zipOutputStream.flush();
        }
        return byteArrayOutputStream.toByteArray();
    }
}

Spring控制器代码

@GetMapping(value = "objectWithDetails/zip", produces = "application/zip")
@RolesAllowed("QUERY_DATA")
public ResponseEntity<byte[]> getObjectWithDetails(String limit, HttpServletResponse response) throws IOException {
    response.setContentType("application/zip");
    List<ObjectSpecification> objectRepresentation = recipeService.getObjectRepresentation(limit);
    byte[] objectsBytes = objectMapper.writeValueAsBytes(objectRepresentation);
    ZipFile zipFile = new ZipFile();
    return ResponseEntity
            .ok()
            .contentType(MediaType.valueOf("application/zip"))
            .header("Content-Encoding", "UTF-8")
            .header("Content-Disposition", String.format("attachment; filename=\"details_%s.zip\"", dateTimeProvider.nowDate()))
            .body(zipFile.createZipByteArray(String.format("details_%s.zip", dateTimeProvider.nowDate()), objectsBytes));
}

问题排查与修复方案

核心问题1:错误设置Content-Encoding头

控制器中添加了Content-Encoding: UTF-8,这个头用于标识文本内容的编码格式,但Zip是二进制文件,添加该头会让Mac的解压工具错误地尝试用UTF-8解码二进制数据,直接导致格式识别失败。

核心问题2(非致命但需修正):Zip内部条目命名不合理

原代码中把Zip包内的文件命名为.zip,但实际内容是JSON字节数组,这种命名会造成混淆,也可能让系统误判文件类型。

修改后的控制器代码

@GetMapping(value = "objectWithDetails/zip", produces = "application/zip")
@RolesAllowed("QUERY_DATA")
public ResponseEntity<byte[]> getObjectWithDetails(String limit) throws IOException {
    List<ObjectSpecification> objectRepresentation = recipeService.getObjectRepresentation(limit);
    byte[] objectsBytes = objectMapper.writeValueAsBytes(objectRepresentation);
    ZipFile zipFile = new ZipFile();
    
    String dateStr = dateTimeProvider.nowDate();
    // 确保日期字符串不包含Mac文件名禁止的字符(如冒号)
    dateStr = dateStr.replaceAll("[:/]", "-");
    
    return ResponseEntity
            .ok()
            .contentType(MediaType.APPLICATION_OCTET_STREAM) // 用二进制流类型更稳妥
            .header("Content-Disposition", String.format("attachment; filename=\"details_%s.zip\"", dateStr))
            .body(zipFile.createZipByteArray(String.format("details_%s.json", dateStr), objectsBytes));
}

额外注意事项

  • 移除了response.setContentType("application/zip"),因为ResponseEntity已经设置了ContentType,重复设置可能引发冲突。
  • 对日期字符串做了特殊字符替换,Mac系统不允许文件名包含冒号、斜杠等字符,避免因文件名非法导致文件损坏。
  • Zip转换类的代码无需修改,try-with-resources的写法在Java 9及以上版本是合法的,若使用Java 8及以下,需调整为:
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
     ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
    // 原有逻辑
}

内容的提问来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 22:05:23