当前位置:   article > 正文

Apache POI处理EXCEL中的图片_poi 图片

poi 图片

1  背景

最近做需求的时候需要做一个导入的功能,通过调研一些java导入的第三方jar包,最后选择了阿里的easyExcel,按照约定的规范能够简单快速的处理excel中的信息,通过@ExcelProperty注解和表头对应解析出excel的信息,使用的过程中发现了两个问题。

  1. 第一个是如果excel中某一行完全是空行的话,excel会直接跳过这一行信息(不知道为什么要这么设计,对于某些业务来说带来一定的不方便性。)
  2. easyExcel不支持导入图片的信息,完全处理不了图片的信息。在github上也得到了回答,不支持处理图片信息

Apache Poi实践

为了处理图片信息,后面在优化的过程中选择用poi处理excel的图片信息,这里做个demo的总结。

  1. public void saveImg(InputStream inputStream) throws Exception {
  2. Map<String, List<PictureData>> pictureMap = ExcelUtil.getWorkbook(inputStream);
  3. Object[] key = pictureMap.keySet().toArray();
  4. for (int i = 0; i < pictureMap.size(); i++) {
  5. // 获取图片索引
  6. String picIndex = key[i].toString();
  7. // 获取图片流
  8. List<PictureData> pictureDataList = pictureMap.get(picIndex);
  9. if (CollectionUtils.isNotEmpty(pictureDataList)) {
  10. pictureDataList.forEach(
  11. pictureData -> {
  12. byte[] data = pictureData.getData();
  13. //图片保存路径
  14. String imgPath = "D:\\image" + System.currentTimeMillis();
  15. FileOutputStream out = null;
  16. try {
  17. out = new FileOutputStream(imgPath);
  18. out.write(data);
  19. out.close();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. });
  24. }
  25. }
  26. }
  1. public static Map<String, List<PictureData>> getWorkbook(InputStream inputStream) {
  2. try {
  3. // 这里要注意下excel表格的格式,不要有多余的空行的情况,否则这里可能会内存溢出,建议用高版本的easyExcel拿到excel的对象。
  4. Workbook workbook = WorkbookFactory.create(inputStream);
  5. Sheet sheet = workbook.getSheetAt(0);
  6. if (sheet instanceof HSSFSheet) {
  7. return getXlsPictures((HSSFSheet) sheet);
  8. } else if (sheet instanceof XSSFSheet) {
  9. return getXlsxPictures((XSSFSheet) sheet);
  10. } else {
  11. return Maps.newHashMap();
  12. }
  13. } catch (Exception e) {
  14. return Maps.newHashMap();
  15. }
  16. }
  1. /**
  2. * 获取图片和位置 (xls)
  3. *
  4. * @param sheet
  5. * @return
  6. */
  7. public static Map<String, List<PictureData>> getXlsPictures(HSSFSheet sheet) {
  8. Map<String, List<PictureData>> map = new HashMap<>();
  9. List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
  10. for (HSSFShape shape : list) {
  11. if (shape instanceof HSSFPicture) {
  12. HSSFPicture picture = (HSSFPicture) shape;
  13. HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
  14. String coordinate = cAnchor.getRow1() + "-" + cAnchor.getCol1();
  15. // 处理一个单元格内有多个图片的情况
  16. if (CollectionUtils.isNotEmpty(map.get(coordinate))) {
  17. map.get(coordinate).add(picture.getPictureData());
  18. } else {
  19. map.put(coordinate, Lists.newArrayList(picture.getPictureData()));
  20. }
  21. }
  22. }
  23. return map;
  24. }
  1. /**
  2. * 获取图片和位置 (xlsx)
  3. *
  4. * @param sheet
  5. * @return
  6. */
  7. public static Map<String, List<PictureData>> getXlsxPictures(XSSFSheet sheet) {
  8. Map<String, List<PictureData>> map = new HashMap<>();
  9. List<POIXMLDocumentPart> list = sheet.getRelations();
  10. for (POIXMLDocumentPart part : list) {
  11. if (part instanceof XSSFDrawing) {
  12. XSSFDrawing drawing = (XSSFDrawing) part;
  13. List<XSSFShape> shapes = drawing.getShapes();
  14. for (XSSFShape shape : shapes) {
  15. XSSFPicture picture = (XSSFPicture) shape;
  16. XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
  17. // 获取excel的行列当作map的key
  18. CTMarker marker = anchor.getFrom();
  19. String coordinate = marker.getRow() + "-" + marker.getCol();
  20. // 处理一个单元格内有多个图片的情况
  21. if (CollectionUtils.isNotEmpty(map.get(coordinate))) {
  22. map.get(coordinate).add(picture.getPictureData());
  23. } else {
  24. map.put(coordinate, Lists.newArrayList(picture.getPictureData()));
  25. }
  26. }
  27. }
  28. }
  29. return map;
  30. }

3  注意事项

1: 利用【XSSFClientAnchor anchor = picture.getPreferredSize()】这种方式获取图片所在坐标时会报空指针异常(在图片粘贴的时候覆盖了单元格之间分界线的情况会有问题),应该用【XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor()】这种方式获取坐标。

2:【Workbook workbook = WorkbookFactory.create(inputStream)】这个方法获取Workbook会很吃机器内存,在excel有很多空行(看似空行,没有数据,其实excel认为不是空行)的时候可能会内存溢出,服务器卡死。

比如要导入的数据是下图所示,不要有多余的空行。

3:导入表格之前先要确定下excel表格的最后一行在哪(可以用ctrl+end确定)?如果发现你的表格的最后一行定位到了空数据的行,如:

你可以选中需要处理的行,然后清除下格式:

 否则系统在用poi处理excel会导致内存溢出,cpu打满(其实是gc线程一直在尝试释放内存)。服务器会在短时间内拒绝服务!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/273094
推荐阅读
相关标签
  

闽ICP备14008679号