4

POI Excel单元格样式超过最大数(4000或64000)的解决方案 - YaenLi

 1 year ago
source link: https://www.cnblogs.com/yaenli/p/17244466.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

POI Excel单元格样式超过最大数(4000或64000)的解决方案

aliases: []
tags   : " #QA #Java "
summary: [POI生成Excel超出的单元格样式的最大数量]
author : [yaenli]
notekey: [20230322-100908]

使用Apache POI生成Excel时,如果创建的单元格样式过多,会报样式超出最大数的错误,

.xls的异常错误:

java.lang.IllegalStateException: The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:1144)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:88)

.xlsx的异常错误:

java.lang.IllegalStateException: The maximum number of Cell Styles was exceeded. You can define up to 64000 style in a .xlsx Workbook
	at org.apache.poi.xssf.model.StylesTable.createCellStyle(StylesTable.java:830)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.createCellStyle(XSSFWorkbook.java:750)

同一个Workbook创建CellStyle有最大数限制,其中.xls(Excel 97) 的最大数是4000,.xlsx(Excel 2007) 的最大数是64000 。

xls 参数限制于org.apache.poi.hssf.usermodel.HSSFWorkbook :

private static final int MAX_STYLES = 4030;

public HSSFCellStyle createCellStyle() {
    if (this.workbook.getNumExFormats() == MAX_STYLES) {
      throw new IllegalStateException("The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook");
    }
    
    ExtendedFormatRecord xfr = this.workbook.createCellXF();
    short index = (short)(getNumCellStyles() - 1);
    return new HSSFCellStyle(index, xfr, this);
}

xlsx 参数限制于org.apache.poi.xssf.model.StylesTable :

private static final int MAXIMUM_STYLE_ID = SpreadsheetVersion.EXCEL2007.getMaxCellStyles();// 64000

public XSSFCellStyle createCellStyle() {
    if (getNumCellStyles() > MAXIMUM_STYLE_ID) {
      throw new IllegalStateException("The maximum number of Cell Styles was exceeded. You can define up to " + MAXIMUM_STYLE_ID + " style in a .xlsx Workbook");
    }
    
    int xfSize = this.styleXfs.size();
    CTXf xf = CTXf.Factory.newInstance();
    xf.setNumFmtId(0L);
    xf.setFontId(0L);
    xf.setFillId(0L);
    xf.setBorderId(0L);
    xf.setXfId(0L);
    int indexXf = putCellXf(xf);
    return new XSSFCellStyle(indexXf - 1, xfSize - 1, this, this.theme);
}

因此,在生成Excel时,如果同一个Workbook不停的创建CellStyle,超限时就会产生样式最大数异常,最直接的体现就是在某些代码中,对每个单元格去独立的设置样式,生成大数据量的Excel报错。

网上最热门的解决方案是所谓的将createCellStyle 放在循环外面,这只能应付表格样式单一的情况。

由于单元格样式CellStyle 并不是单元独立拥有的,每个单元格只是保存了样式的索引,一般的Excel真正使用到的样式也不会超过4000/64000 ,因此更好的解决方案是实现单元格样式的复用(注意不同的Workbook创建的CellStyle是不能混用的)。

方案1:缓存样式实现复用

提取样式关键字作为key,将CellStyle缓存至Map:

Workbook workBook = new HSSFWorkbook();// or new XSSFWorkbook();
Sheet sheet = workBook.createSheet(strSheetName);
Map cellStyleMap = new HashMap<String, CellStyle>();// 缓存样式

// 样式代码
for (int rowIndex = 0; rowIndex < maxRow; rowIndex++) {
    Row row = sheet.createRow(rowIndex);
    for (int colIndex = 0; colIndex < maxCol; colIndex++) {
        Cell cell = row.createCell((short) colIndex);
        String styKey = getCellStyleKey(rowIndex, colIndex);// 根据获取样式key
        CellStyle cellStyle = (CellStyle) cellStyleMap.computeIfAbsent(styKey, k-> workBook.createCellStyle());// 获取样式
        cell.setCellStyle(cellStyle);
    }
}

方案2:修改限制参数

修改POI中的限制参数( org.apache.poi.hssf.usermodel.HSSFWorkbook.MAX_STYLESorg.apache.poi.ss.SpreadsheetVersion.EXCEL2007)。

过多的创建样式会影响性能,建议仅在真正使用的样式超过限制时再去修改此参数。

方案3:延迟指定单元格样式实现复用

参见文章:
POI 操作Excel的单元格样式超过64000的异常问题解决
根据模版填充Excel并导出的工具 · GitCode

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK