LZYTJX 2024-02-01 18:01 采纳率: 66.7%
浏览 8

java使用ZipOutputStream

带附件下载的时候,双击ZIP文件提示失效,但是可以解压;不带附件下载的时候,双击ZIP文件,可以直接打开,具体是哪里有错误,麻烦各位指教一下


public ModelAndView dowmSelFileAndLaws(String selIds, String lawsApplyModule, String hasLawsApplyModule, String name, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.setView(new DownloadView());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 创建一个ZipOutputStream对象
        ZipOutputStream zipOut = new ZipOutputStream(baos, StandardCharsets.UTF_8);
        zipOut.setMethod(ZipOutputStream.DEFLATED);
        zipOut.setLevel(Deflater.DEFAULT_COMPRESSION);
        List<String>tmpIds = Lists.newArrayList();
        if (StringUtils.isNotEmpty(selIds)) {
            tmpIds = Arrays.asList(selIds.split(","));
            if (tmpIds != null && tmpIds.size() > 0) {
                if (tmpIds.size() == 1) {
                    LawsDetailsDto dto = new LawsDetailsDto();
                    dto.setLawId(tmpIds.get(0));
                    dto.setLawsApplyModule(lawsApplyModule);
                    dto.setHasLawsApplyModule(hasLawsApplyModule);
                    LawDownDto lawDownDto = lawsSearchService.getLawDownDto(dto);
                    // 下载法规 doc 文档
                    InputStream lawInputStream = lawsSearchService.getLawInputStream(lawDownDto, dto);
                    ZipEntry zipLawsEntry = new ZipEntry(lawDownDto.getLawsName() + ".docx");
                    zipOut.putNextEntry(zipLawsEntry);
                    byte[] buffer = new byte[1024];
                    int lenLaws;
                    while ((lenLaws = lawInputStream.read(buffer)) > 0) {
                        zipOut.write(buffer, 0, lenLaws);
                    }
                    lawInputStream.close();
                    //获取附件
                    if (lawDownDto.getAttFiles() != null) {
                        for (Map.Entry<String, String> entry : lawDownDto.getAttFiles().entrySet()) {
                            AttachmentExample example = new AttachmentExample();
                            example.createCriteria().andAttNameEqualTo(entry.getKey());
                            List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
                            for (Attachment attachment : attachmentList) {
                                fileService.countDownloadNum(attachment.getId(), "true");
                                Map<String, Object> fileInfo = fileService.getCloudFileInfo(attachment.getId());
                                ZipEntry zipFileEntry = new ZipEntry(fileInfo.get("fileName") + ".docx");
                                zipOut.putNextEntry(zipFileEntry);
                                byte[] bufferFile = new byte[1024];
                                int lenFile;
                                InputStream is = (InputStream) fileInfo.get("fileBytes");
                                while ((lenFile = is.read(bufferFile)) > 0) {
                                    zipOut.write(bufferFile, 0, lenFile);
                                }
                                is.close();
                            }
                        }
                        zipOut.closeEntry();
                        // 将生成的ZIP文件写入一个ByteArrayOutputStream对象中
                        zipOut.finish();
                        byte[] bytes = baos.toByteArray();
                        baos.write(bytes, 0, bytes.length);
                        baos.flush();
                        baos.close();
                        // 将ByteArrayOutputStream对象转换为一个ByteArrayInputStream对象
                        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                        mv.addObject(DownloadView.EXPORT_FILE, bais);
                        mv.addObject(DownloadView.EXPORT_FILE_NAME, lawDownDto.getLawsName() + ".zip");
                        mv.addObject(DownloadView.EXPORT_FILE_TYPE, MediaType.ZIP.toString());
                        mv.setView(new DownloadView());
                        response.setHeader("fileName", java.net.URLEncoder.encode(lawDownDto.getLawsName() + ".zip", "utf-8"));
                    } else {
                        zipOut.closeEntry();
                        // 将生成的ZIP文件写入一个ByteArrayOutputStream对象中
                        zipOut.finish();
                        byte[] bytes = baos.toByteArray();
                        baos.write(bytes, 0, bytes.length);
                        baos.flush();
                        baos.close();
                        // 将ByteArrayOutputStream对象转换为一个ByteArrayInputStream对象
                        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                        mv.addObject(DownloadView.EXPORT_FILE, bais);
                        mv.addObject(DownloadView.EXPORT_FILE_NAME, lawDownDto.getLawsName() + ".docx");
                        mv.addObject(DownloadView.EXPORT_FILE_TYPE, DownloadView.FILE_TYPE.DOCX);
                        mv.setView(new DownloadView());
                        response.setHeader("fileName", java.net.URLEncoder.encode(lawDownDto.getLawsName() + ".docx", "utf-8"));
                    }
                } else {
                    //多选,最后肯定是一整个压缩包,1有附件,里面就带文件夹(法规文档+附件),2无附件,里面法规docx,最后把这些都放到压缩包中
                    //循环开始
                    for (String lawsId : tmpIds) {
                        LawsDetailsDto dto = new LawsDetailsDto();
                        dto.setLawId(lawsId);
                        dto.setLawsApplyModule(lawsApplyModule);
                        dto.setHasLawsApplyModule(hasLawsApplyModule);
                        //根据传来的查看基本信息
                        LawDownDto lawDownDto = lawsSearchService.getLawDownDto(dto);

                        // 判断是否有附件
                        if (lawDownDto.getAttFiles() != null) {
                            // 创建一个文件夹,用于存放法规和附件的doc文件
                            String folderName = lawDownDto.getLawsName();
                            ZipEntry folderEntry = new ZipEntry(folderName + "/");
                            zipOut.putNextEntry(folderEntry);

                            //把法规文件放到这个文件夹中
                            InputStream lawInputStream = lawsSearchService.getLawInputStream(lawDownDto, dto);
                            ZipEntry zipLawsEntry = new ZipEntry(folderName + "/" + lawDownDto.getLawsName() + ".docx");
                            zipOut.putNextEntry(zipLawsEntry);
                            byte[] buffer = new byte[1024];
                            int lenLaws;
                            while ((lenLaws = lawInputStream.read(buffer)) > 0) {
                                zipOut.write(buffer, 0, lenLaws);
                            }
                            lawInputStream.close();

                            //把附件文件放到这个文件夹中
                            for (Map.Entry<String, String> entry : lawDownDto.getAttFiles().entrySet()) {
                                AttachmentExample example = new AttachmentExample();
                                example.createCriteria().andAttNameEqualTo(entry.getKey());
                                List<Attachment> attachmentList = attachmentMapper.selectByExample(example);
                                for (Attachment attachment : attachmentList) {
                                    fileService.countDownloadNum(attachment.getId(), "true");
                                    Map<String, Object> fileInfo = fileService.getCloudFileInfo(attachment.getId());
                                    ZipEntry zipFileEntry = new ZipEntry(folderName + "/" + attachment.getAttName());
                                    zipOut.putNextEntry(zipFileEntry);
                                    byte[] bufferFile = new byte[1024];
                                    int lenFile;
                                    InputStream is = (InputStream) fileInfo.get("fileBytes");
                                    while ((lenFile = is.read(bufferFile)) > 0) {
                                        zipOut.write(bufferFile, 0, lenFile);
                                    }
                                    is.close();
                                    zipOut.closeEntry();
                                }
                            }
                            
                        } else {
                            //没附件 
                            //下载法规 doc 文档
                            InputStream lawInputStream = lawsSearchService.getLawInputStream(lawDownDto, dto);
                            ZipEntry zipLawsEntry = new ZipEntry(lawDownDto.getLawsName() + ".docx");
                            zipOut.putNextEntry(zipLawsEntry);
                            byte[] buffer = new byte[1024];
                            int lenLaws;
                            while ((lenLaws = lawInputStream.read(buffer)) > 0) {
                                zipOut.write(buffer, 0, lenLaws);
                            }
                            lawInputStream.close();
                            zipOut.closeEntry();
                        }
                    }
                    
                    // 在循环外部调用 finish() 方法,将所有法规和附件的压缩文件写入到字节数组中
                    zipOut.finish();
                    
                    byte[] bytes = baos.toByteArray();
                    baos.write(bytes, 0, bytes.length);
                    baos.flush();
                    baos.close();

                    // 将ByteArrayOutputStream对象转换为一个ByteArrayInputStream对象
                    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                    String fileName = null;
                    if (StringUtils.isNotEmpty(name)) {
                        fileName = "[" + name + "号法规文件]";
                    } else {
                        fileName = "所选法规文件及附件下载" + System.currentTimeMillis();
                    }
                    if (StringUtils.isNotBlank(fileName)) {
                        fileName = new String(fileName.getBytes(), "utf-8");
                    }

                    mv.addObject(DownloadView.EXPORT_FILE, bais);
                    mv.addObject(DownloadView.EXPORT_FILE_NAME, fileName + ".zip");
                    mv.addObject(DownloadView.EXPORT_FILE_TYPE, MediaType.ZIP);
                    mv.setView(new DownloadView());
                    response.setHeader("fileName", java.net.URLEncoder.encode(fileName + ".zip", "utf-8"));
                }

            }
        }    
        
    
        return mv;
    }
  • 写回答

3条回答 默认 最新

  • 叫兽-郭老师 Java领域新星创作者 2024-02-01 18:05
    关注

    参考通义千问和郭老师的小迷弟雅思莫了-编写提供,主要是为了帮助您快速解决问题,如下回答,您可以参考下,如有问题,评论区留言。

    从你提供的代码来看,问题可能出在以下几点:

    1. ZipEntry的closeEntry()方法调用位置zipOut.closeEntry(); 应该放在每个文件写入完毕后立即关闭,而不是所有文件都写完之后再调用。例如,在写入附件文档后应立即调用 zipOut.closeEntry()

    2. 循环内部和外部的finish()调用:在多文件循环中,你应该确保在一个法规的所有附件写入完成后才调用 zipOut.finish(),而不是每次写入一个附件就调用一次(这可能会导致 ZIP 文件格式错误)。现在你的代码里,这个方法在循环外部调用是正确的。

    3. 文件名编码问题:虽然你在设置HTTP响应头时使用了URLEncoder.encode对文件名进行编码,但是创建ZipEntry时没有做同样的处理。如果文件名包含非ASCII字符,可能导致ZIP文件内部存储的文件名与实际文件名不匹配,从而无法双击打开。创建ZipEntry时可以尝试加上编码,例如:

      ZipEntry zipLawsEntry = new ZipEntry(lawDownDto.getLawsName() + ".docx".getBytes(StandardCharsets.UTF_8));
      

      但请注意,ZipEntry构造函数并不支持直接传入字节数组作为名称,需要转换为String。若ZipEntry本身不支持UTF-8编码的文件名,你可能需要在构造文件名字符串时就进行编码转换,并确保解压工具能正确识别UTF-8编码的ZIP文件名。

    4. 附件扩展名问题:你的附件下载部分,硬编码了.docx作为所有附件的扩展名,这可能导致实际附件类型和扩展名不符。应该根据附件的实际类型来设置正确的扩展名。

    修正后的部分代码示例:

    ...
    InputStream is = (InputStream) fileInfo.get("fileBytes");
    ZipEntry zipFileEntry = new ZipEntry(folderName + "/" + attachment.getAttName() + "." + getAttachmentExtension(fileInfo)); // 获取真实的附件扩展名
    zipOut.putNextEntry(zipFileEntry);
    while ((lenFile = is.read(bufferFile)) > 0) {
        zipOut.write(bufferFile, 0, lenFile);
    }
    is.close();
    zipOut.closeEntry(); // 在每次写入附件后关闭entry
    ...
    
    // 获取附件扩展名的方法
    private String getAttachmentExtension(Map<String, Object> fileInfo) {
        // 根据实际情况获取并返回附件的真实扩展名
    }
    
    // 循环结束后统一调用 finish()
    ...
    zipOut.finish();
    ...
    

    请检查并修改以上指出的潜在问题点,然后测试是否能够正常打开ZIP文件。

    评论

报告相同问题?

问题事件

  • 创建了问题 2月1日

悬赏问题

  • ¥15 求一份STM32F10X的I2S外设库
  • ¥15 android 打包报错
  • ¥15 关于stm32的问题
  • ¥15 ncode振动疲劳分析中,noisefloor如何影响PSD函数?
  • ¥50 寻找fpga的benchmark
  • ¥50 如何在arduino上,实现用4×4矩阵键盘按键控制2004显示屏输出图中显示功能的代码?
  • ¥15 P1口接8个发光二极管,利用定时计数器1编写程序
  • ¥20 keil5编译找不到.h文件该如何解决
  • ¥15 安卓EVS如何开启服务正常实现功能
  • ¥15 canal读取mysql时报错