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


    问题现象

    使用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();// 缓存样式
    
    // 样式代码
    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__

  • 本文作者: 木子一叶
  • 本文链接: https://www.cnblogs.com/yaenli/p/17244466.html
  • 关于博主: I am a good man 有问题请留言或私信我
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    RPA是什么,对你有什么用?
    01标定相关理论
    块链串的实现(c语言)
    【相机标定】opencv python 标定相机内参时不计算 k3 畸变参数
    探索 Material 3:全新设计系统和组件库的介绍
    Swift 周报 第十期
    [Power Query] 添加列
    c语言-函数-009
    Mac m1配置MAMP+PHPStorm环境
    关于小程序 scroll
  • 原文地址:https://www.cnblogs.com/yaenli/p/17244466.html