赞
踩
最近做需求的时候需要做一个导入的功能,通过调研一些java导入的第三方jar包,最后选择了阿里的easyExcel,按照约定的规范能够简单快速的处理excel中的信息,通过@ExcelProperty注解和表头对应解析出excel的信息,使用的过程中发现了两个问题。
为了处理图片信息,后面在优化的过程中选择用poi处理excel的图片信息,这里做个demo的总结。
- public void saveImg(InputStream inputStream) throws Exception {
- Map<String, List<PictureData>> pictureMap = ExcelUtil.getWorkbook(inputStream);
-
- Object[] key = pictureMap.keySet().toArray();
- for (int i = 0; i < pictureMap.size(); i++) {
- // 获取图片索引
- String picIndex = key[i].toString();
- // 获取图片流
- List<PictureData> pictureDataList = pictureMap.get(picIndex);
- if (CollectionUtils.isNotEmpty(pictureDataList)) {
- pictureDataList.forEach(
- pictureData -> {
- byte[] data = pictureData.getData();
- //图片保存路径
- String imgPath = "D:\\image" + System.currentTimeMillis();
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(imgPath);
- out.write(data);
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- });
- }
- }
- }
- public static Map<String, List<PictureData>> getWorkbook(InputStream inputStream) {
- try {
- // 这里要注意下excel表格的格式,不要有多余的空行的情况,否则这里可能会内存溢出,建议用高版本的easyExcel拿到excel的对象。
- Workbook workbook = WorkbookFactory.create(inputStream);
- Sheet sheet = workbook.getSheetAt(0);
- if (sheet instanceof HSSFSheet) {
- return getXlsPictures((HSSFSheet) sheet);
- } else if (sheet instanceof XSSFSheet) {
- return getXlsxPictures((XSSFSheet) sheet);
- } else {
- return Maps.newHashMap();
- }
- } catch (Exception e) {
- return Maps.newHashMap();
- }
- }
- /**
- * 获取图片和位置 (xls)
- *
- * @param sheet
- * @return
- */
- public static Map<String, List<PictureData>> getXlsPictures(HSSFSheet sheet) {
- Map<String, List<PictureData>> map = new HashMap<>();
- List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
- for (HSSFShape shape : list) {
- if (shape instanceof HSSFPicture) {
- HSSFPicture picture = (HSSFPicture) shape;
- HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
- String coordinate = cAnchor.getRow1() + "-" + cAnchor.getCol1();
- // 处理一个单元格内有多个图片的情况
- if (CollectionUtils.isNotEmpty(map.get(coordinate))) {
- map.get(coordinate).add(picture.getPictureData());
- } else {
- map.put(coordinate, Lists.newArrayList(picture.getPictureData()));
- }
- }
- }
- return map;
- }
- /**
- * 获取图片和位置 (xlsx)
- *
- * @param sheet
- * @return
- */
- public static Map<String, List<PictureData>> getXlsxPictures(XSSFSheet sheet) {
- Map<String, List<PictureData>> map = new HashMap<>();
- List<POIXMLDocumentPart> list = sheet.getRelations();
- for (POIXMLDocumentPart part : list) {
- if (part instanceof XSSFDrawing) {
- XSSFDrawing drawing = (XSSFDrawing) part;
- List<XSSFShape> shapes = drawing.getShapes();
- for (XSSFShape shape : shapes) {
- XSSFPicture picture = (XSSFPicture) shape;
- XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
- // 获取excel的行列当作map的key
- CTMarker marker = anchor.getFrom();
- String coordinate = marker.getRow() + "-" + marker.getCol();
- // 处理一个单元格内有多个图片的情况
- if (CollectionUtils.isNotEmpty(map.get(coordinate))) {
- map.get(coordinate).add(picture.getPictureData());
- } else {
- map.put(coordinate, Lists.newArrayList(picture.getPictureData()));
- }
- }
- }
- }
- return map;
- }
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线程一直在尝试释放内存)。服务器会在短时间内拒绝服务!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。