前言
公司存在很多excel含图片导出,因为提供给客户的excel可能还会打印出来,所以图片不能存链接。真坑!!!
一步步解决原理
使用这个SXSSFWorkbook进行excel导出,不了解的可以看我的这个博客
异步导出
压缩导出
- 建议压缩图片导出:因为压缩图片后导出可以支撑更多的数据量,但还是因服务器内存而定。
- 不建议不压缩导出:因不压缩图片的数据量巨大,特别能吃内存。可能会导不出,不建议使用
SXSSFWorkbook图片没缓存在磁盘上
因为我们都知道SXSSFWorkbook有个操作窗口,默认100条数据在内存,多余的数据会缓存在磁盘中,追加图片的源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36public int addPicture(byte[] pictureData, int format) {
// 获取所有图片
int imageNumber = getAllPictures().size() + 1;
XSSFPictureData img = (XSSFPictureData)createRelationship(XSSFPictureData.RELATIONS[format], XSSFFactory.getInstance(), imageNumber, true);
try {
OutputStream out = img.getPackagePart().getOutputStream();
out.write(pictureData);
out.close();
} catch (IOException e){
throw new POIXMLException(e);
}
pictures.add(img);
return imageNumber - 1;
}
/**
* Gets all pictures from the Workbook.
*
* @return the list of pictures (a list of {@link XSSFPictureData} objects.)
* @see #addPicture(byte[], int)
*/
public List<XSSFPictureData> getAllPictures() {
if(pictures == null){
List<PackagePart> mediaParts = getPackage().getPartsByName(Pattern.compile("/xl/media/.*?"));
pictures = new ArrayList<XSSFPictureData>(mediaParts.size());
for(PackagePart part : mediaParts){
pictures.add(new XSSFPictureData(part, null));
}
}
return pictures; //YK: should return Collections.unmodifiableList(pictures);
}
/**
* excel中追加的图片以XSSFPictureData对象,存在内存中
*/
private List<XSSFPictureData> pictures;
分页导出
- 缘由:即便是压缩导出,仍存在上限。假设每条记录含9张图片,每张图片大小为100k。一条记录算1mb,1000条数据基本占1g内存,而你的服务运行内存也就1g,也就说压缩最多导1000条就撑死了。
- 引出:既然一个excel承载不了这么多,那就把它拆成多个导出excel,比如200条一个excel,最后将生成的多个excel压缩成一个压缩包提供给用户下载。
- 结论:分页导出功能生成的压缩包里是多个较小的excel。因为即便导出一个很大的excel给到用户也没有意义,因为这跟打不开。多个较小可以较为流畅的打开。可以承载更大数据量,理论上磁盘有多大,就可以存多少excel。