记录Zip4j压缩文件解压后文件显示异常

场景:从金山云链接中读取文件流,将文件保存到本地,然后将本地文件压缩成zip包通过接口传给前端页面

现象:图片及word显示异常

原图:
在这里插入图片描述解压后:
在这里插入图片描述

用到工具zip4j
直接上代码
第一步,从云链接中获取输入流并保存为本地文件

	/**
     * 将金山云文件写入到本地
     */
    public static void writeKs3FileToLocal(String ks3Url, String localFilePath) {
        try {
            URL url = new URL(ks3Url);
            InputStream inputStream = url.openStream();
            FileOutputStream fos = new FileOutputStream(localFilePath);
            byte[] b = new byte[1024];
            while ((inputStream.read(b)) != -1) {
                fos.write(b);// 写入数据
            }
            inputStream.close();
            fos.close();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

第二步,压缩本地文件

public void exportAttachment(String encryptPerformanceId, HttpServletResponse response) {
		//获取数据库中附件列表
        List<ExportAttachmentDao> attachmentList = attachmentService.getAttachmentByPerformanceId(performanceId);
        //添加压缩文件
        log.info("生成临时压缩文件:{}", zipPath);
        ZipFile zipFile = new ZipFile(zipPath);
        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionLevel(CompressionLevel.FASTEST);//压缩比最小,速度最快
        parameters.setCompressionMethod(CompressionMethod.STORE);//不压缩,防止压缩后解压打开异常
        attachmentList.forEach(attachment -> {
                String filePath = eachPersonFileDir + attachment.getFileName();
                //将金山云文件保存成本地文件
                ZipUtils.writeKs3FileToLocal(attachment.getPath(), filePath);
                //将本地文件添加到zip
                File localFile = new File(filePath);
                zipFile.addFile(localFile, parameters);
                log.info("文件[name={},path={}]将添加到压缩文件", attachment.getFileName(), attachment.getPath());
                //删除本地文件
//                localFile.delete();
        });
        String zipFileName = performance.getEid() + ".zip";
        writeZip(response, zipFile.getFile(), zipFileName);
        log.info("删除临时压缩文件:{}", zipPath);
//        zipFile.getFile().delete();
    }

第三步:返回给前端文件流

public void writeZip(HttpServletResponse resp, File zipFile, String zipFileName) {
        log.info("下载文件[name={},size={}]", zipFileName, zipFile.length());
        InputStream is = null;
        BufferedInputStream bs = null;
            is = new FileInputStream(zipFile);
            bs = new BufferedInputStream(is);
            resp.setHeader("Content-disposition", "attachment;filename=" + zipFileName);
            resp.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
            byte[] bytes = new byte[1024 * 10];
            int read = 0;
            ServletOutputStream outputStream = resp.getOutputStream();
            while ((read = bs.read(bytes, 0, 1024 * 10)) != -1) {
                outputStream.write(bytes, 0, read);
            }
    }

原因分析:

1,可能是图片压缩导致的,设置了压缩参数:最快,不压缩
结果还是有问题
2,猜测是获取金山云文件流保存到本地有问题,注释了删除本地文件的代码,从服务器上下载本地文件,果然,本地文件就是异常的图片。然后分析第一步的云链接保存为本地图片,发现写法有误,应为:

public static void writeKs3FileToLocal(String ks3Url, String localFilePath) {
        try {
            URL url = new URL(ks3Url);
            InputStream inputStream = url.openStream();
            FileOutputStream fos = new FileOutputStream(localFilePath);
            byte[] b = new byte[1024];
            int length;
            while ((length = inputStream.read(b)) > 0) {
                fos.write(b, 0, length);
            }
            fos.close();
            inputStream.close();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

真实的区别在于这句
fos.write(b); <=> fos.write(b, 0, length);
这两句有啥区别呢,我们看下原码:

public void write(byte b[]) throws IOException {
        writeBytes(b, 0, b.length, append);
    }
public void write(byte b[], int off, int len) throws IOException {
        writeBytes(b, off, len, append);
    }

如果只传字节数组b,则写入的length为b.length=1024,而不是实际读取到的有效数据,而最后一次b.length=1024(固定值,定义的数组长度),length=375,写入了一些无效的字节导致图片异常,下图是最后一次读取的结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值