用java导入导出zip文件

  • Post author:
  • Post category:java


zip导入

public SwaggerResultUtil<String> importDefinition(@RequestParam(value = "file") MultipartFile file) {
        SwaggerResultUtil<String> resultUtil;
        String fileName = file.getOriginalFilename();
        ZipInputStream zs = null;
        BufferedInputStream bs = null;
        try {
            String extension = FilenameUtils.getExtension(fileName);
            if (extension.equals("zip")) {
                zs = new ZipInputStream(file.getInputStream(), Charset.forName("GBK"));// 中文文件名
                bs = new BufferedInputStream(zs);
                List<ProcessDefinitionEntity> entities = new ArrayList<>();
                ZipEntry ze;
                while ((ze = zs.getNextEntry()) != null) { // 获取zip包中的每一个zip file entry
                    long size = ze.getSize();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] bytes = null;
                    if (size == -1) { // 当你的文件是程序导出,且没指定长度时可能发生这类情况,长度为-1,但是有内容。
                        while (true) {
                            int zsize = zs.read();
                            if (zsize == -1) {
                                break;
                            }
                            baos.write(zsize);
                        }
                    } else {
                        bytes = new byte[(int) size];
                        bs.read(bytes, 0, (int) ze.getSize());
                    }
                }
                resultUtil = definitionService.insertSelectiveBatch(entities);
            } else {
                resultUtil = SwaggerResultUtil.resultError(ErrorCodeEnum.INCORRECT_FILE_FORMAT.getCode(), ErrorCodeEnum.INCORRECT_FILE_FORMAT.getMsg());
            }
        } catch (Exception e) {
            logger.error("转换流时发生异常!", e);
            resultUtil = SwaggerResultUtil.error500("文件内容格式有误!");
        } finally {
            try {
                bs.close();
                zs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultUtil;
    }

有几个注意点已经加了注释

1.当zip包里面的文件有中文名时, zs = new ZipInputStream(file.getInputStream(), Charset.forName(“GBK”));此行代码请指定编码为gbk。

2.当long size = ze.getSize();zip包里面的entry有流数据但是长度为-1时,特殊处理,直接读取到流结束,一般出现这种情况的原因是用程序导出,且没有指定长度(看下面的导出方法)时造成的,当你操作一下这个文件后会自动加上长度,比如给改文件名等。

zip导出

public void exportDefinition(
            @ApiParam(name = "definitionIds",value = "流程定义id【多个用英文,分隔】",required = true) @RequestParam String definitionIds, HttpServletResponse response) {
        if (StringUtils.isNotEmpty(definitionIds)) {
            String[] ids = definitionIds.split(",");
            List<ProcessDefinitionEntityWithBLOBs> blobs = definitionService.getDefinitionListByIds(Arrays.asList(ids));
            if (CollectionUtils.isNotEmpty(blobs)) {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                try (ZipOutputStream zip = new ZipOutputStream(outputStream)) {
                    for (ProcessDefinitionEntityWithBLOBs bs : blobs) {
                        CommonUtil.createZip(bs.getName(), bs.getJsonBytes(), zip);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    IOUtils.write(outputStream.toByteArray(), response.getOutputStream());
                    response.setHeader("Content-Disposition", "attachment; filename=flow.zip");
                    response.flushBuffer();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
 /**
     * @param entryName zip中的文件名
     * @param srcByte 二进制数据
     * @param zip  zip输出流
     */
    public static void createZip(String entryName, byte[] srcByte, ZipOutputStream zip) {
        try {
            zip.putNextEntry(new ZipEntry(entryName + ".flow"));
            IOUtils.write(srcByte, zip);
            zip.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

导出时未指定长度就会发生上面导入时提到的问题。

class ZipEntry implements ZipConstants, Cloneable {

    String name;        // entry name
    long xdostime = -1; // last modification time (in extended DOS time,
                        // where milliseconds lost in conversion might
                        // be encoded into the upper half)
    FileTime mtime;     // last modification time, from extra field data
    FileTime atime;     // last access time, from extra field data
    FileTime ctime;     // creation time, from extra field data
    long crc = -1;      // crc-32 of entry data
    long size = -1;     // uncompressed size of entry data
    long csize = -1;    // compressed size of entry data
    int method = -1;    // compression method
    int flag = 0;       // general purpose flag
    byte[] extra;       // optional extra field data for entry
    String comment;     // optional comment string for entry

注意:导入导出结束关闭流且要顺序正确,先打开的后关闭,不然解压时会报“不可预料的压缩文件末端”。



版权声明:本文为zpfzly原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。