Java解析上传的zip文件--包含Excel解析与图片上传

发布时间 2023-11-17 23:56:32作者: ProsperousEnding

Java解析上传的zip文件--包含Excel解析与图片上传

前言:今天遇到一个需求:上传一个zip格式的压缩文件,该zip中包含人员信息的excel以及excel中每行对应的人的图片,现在需要将该zip压缩包中所有内容解析导入到数据库中,包括图片,并将图片与excel内容对应。

代码演示:

/**
* 信息导入Controller
*/
@RestController
@RequestMapping("/import")
public class ImportController {
    
    
   @AutoWired
   private IExcelService excelService

    /**
    * 接收zip
    * zip中包含了人员excel以及excel中每行对应的人员图片--默认每个人员图片的名称为number号
    */
    @PostMapping(value = "/zip")
    @Transactional
    public void sendRequest(@RequestParam("file") MultipartFile zipFile) throws IOException {
        //通过zip名称创建一个file文件-该文件无具体路径
          File file = new File(Objects.requireNonNull(zipFile.getOriginalFilename()));
        //将zip写入到file中
          FileUtils.writeByteArrayToFile(file, zipFileFile.getBytes());
        //设定字符集编码--这一步必须,否则放到linux服务器中会有字符集报错
          Charset charset = Charset.forName("GBK");
          ZipFile zipFile = new ZipFile(file, charset);
        //开始读取zip中文件
          Enumeration<? extends ZipEntry> entries = zipFile.entries();
        //创建excelZip存放zip中的excel文件内容
          List<ZipEntry> excelZip = new ArrayList<ZipEntry>();
        //创建imgZip存放zip中的图片文件
          List<ZipEntry> imgZip = new ArrayList<ZipEntry>();
        
        //开始读取zip文件
    	  while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
              //通过文件名称去过滤出excel
            if (entry.getName().contains("/excel表格名称.xlsx")) {
                excelZip.add(entry);
            }
              //获取包含图片目录下所有的图片信息
            if (!entry.isDirectory() && entry.getName().contains("图片目录的名称")) {
                imgZip.add(entry);
            }
        }
        //创建文件输入流,将excel变为流
         InputStream excelInputStream = zipFile.getInputStream(excelZip.get(0));
        //创建EasyExcel中的监听器
         ExcelListener excelListener = new ExcelListener();
        //调用EasyExcel中的EasyExcelFactory方法去读取输入流
        EasyExcelFactory.read(excelInputStream,Excel.class,excelListener).sheet().doRead();
        //到此完成获取压缩包中excel的人员信息
        List<Excel> excelList = excelListener.getDataList();
        
        //遍历读取图片
        imgZip.stream().forEach(zip -> {
        try {
             //创建压缩图片的输入流
               InputStream imgInputStream = zipFile.getInputStream(zip);
             //调用流转文件的方法
               File img = stream2file(imgInputStream);
               for (Excel excel : excelList) 
               {
                //将去除后缀的压缩图片名称与excel中的人员号码字段做比较
                if (removeExtension(zip.getName()).contains(excel.getNum())) {
                    //调用文件上传接口,上传到服务器目录下,并返回文件存储路径
                    //这边FileUpload.upload为自己写的一个上传接口,此处省略。。。
                    //如果接受对象为MultipartFile,还需调用fileToMultipartFile转换
                        String urlPath =FileUpload.upload(fileToMultipartFile(img));
                    //进行对象的保存
                        Excel e=new Excel();
                    //设置存储的图片地址
                        e.setPath(urlPath);
                    //调用存储接口存储图片与excel信息
                        excelService.insert(e);
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

   //设置文件名前缀;必须至少三个字符
    static final String PREFIX = "stream2file";
    //设置定义文件的后缀扩展名;如果为null,则将使用后缀".tmp"
    //这边为图片格式,所以默认给的后缀为jpg格式
    static final String SUFFIX = ".jpg";
    
   /**
    * 输入流转文件
    * 该方法为在内存中创建临时文件,不进行磁盘存储
    */
    public static File stream2file(InputStream in) throws IOException {
        //创建临时文件
        final File tempFile = File.createTempFile(PREFIX, SUFFIX);
        tempFile.deleteOnExit();
        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            IOUtils.copy(in, out);
        }
        return tempFile;
    }
    
   /**
    * 截取文件名称--去除后缀名(.jpg等)
    */
    public static String removeExtension(String fileName) {
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1) {
            // 如果文件名中没有后缀,则返回原文件名
            return fileName;
        } else {
            // 截取从开头到最后一个`.`字符之前的部分
            return fileName.substring(0, lastDotIndex);
        }
    }
    
     /**
     * file转MultipartFile
     *
     * @param file file
     * @return MultipartFile
     */
    public static MultipartFile fileToMultipartFile(File file) {
        MultipartFile result = null;
        if (null != file) {
            try (FileInputStream input = new FileInputStream(file)) {
                result = new MockMultipartFile(file.getName().concat("temp"), file.getName(), "text/plain", input);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
   }  
}

回顾:

博主解答思路为:

  1. 接收压缩文件
  2. 解析压缩文件,并区分excel与图片文件
  3. 将excel与图片进行匹配,将匹配成功的数据存储到数据库中

要点:

  1. 本次读取几乎都是内存读取,将数据读取到内存中,也在磁盘中建立了临时文件
  2. 解析时需要进行多次类型转换
  3. new ZipFile(file, charset)这一步一定要设定字符集编码,并查看window与linux字符集编码的区别,否则会因为字符集编码问题报错而无法运行