问题描述
采用jxl处理 excel文件生成时,产生如下报错:
Warning: Maximum number of format records exceeded. Using default format.
Warning: Maximum number of format records exceeded. Using default format.
Warning: Maximum number of format records exceeded. Using default format.
相关代码:
for (int j = 0; j < colNames.length; j++){
// 根据 column format 格式来写入
String format = colFormats[j];
if ( format != null && format.length()>0) {
WritableCellFormat wcf = new WritableCellFormat(new NumberFormat(format)); // 设置数字格式,例如:"#0.00"
BigDecimal val =(BigDecimal) maptemp.get(colNames[j]);
jxl.write.Number labelNF = new jxl.write.Number(j, rowNum, val.doubleValue(), wcf); // 格式化数值
sheet.addCell(labelNF);
} else {
// 否则按照字符串文本格式来处理
sheet.addCell(new Label(j, rowNum, StringDateUtil.obj2Str(maptemp.get(colNames[j]))));
}
}
在添加单元格时,需要提供相关格式信息。因此,在for循环内部,new了很多WritableCellFormat对象出来,以至于超过jxl内部约束的format records最大数限制。
原因分析
一方面,jxl允许的每个workbook(一个excel文件)中的WritableCellFormat对象个数不超过441个,超过部分的单元格格式会自动丢弃,转而采用默认格式代替,并提示如上所述的warning信息。
相关源码:
//jxl.biff.FormattingRecords
private static final int maxFormatRecordsIndex = 0x1b9;
另一方面,其实这些 单元格格式对象(WritableCellFormat对象)是可以复用的,没有必要为每个单元格重复创建如此多的格式对象。
解决方法
通过对需求的分析,我们期望生成的excel表格,不太可能存在超过400多个以上的格式。因此,我们可以将这些格式对象只创建一次,并保存到Map容器里,在使用时,按照format格式,找到相应的对象并使用。
如下是修改后的代码:
HashMap<String, WritableCellFormat> wcfMap = new HashMap<String, WritableCellFormat>();
for (int j = 0; j < colNames.length; j++){
// 根据 column format 格式来写入
String format = colFormats[j];
if ( format != null && format.length()>0) {
// WritableCellFormat wcf = new WritableCellFormat(new NumberFormat(format)); // 设置数字格式,例如:"#0.00"
// 这里不需要 new 这么多的 单元格格式对象!
// 只有在format不同时,才创建对象,否则复用已有对象即可!
WritableCellFormat wcf = null;
if (wcfMap.containsKey(format)) {
wcf = wcfMap.get(format);
} else {
wcf = new WritableCellFormat(new NumberFormat(format)); // 设置数字格式,例如:"#0.00"
wcfMap.put(format, wcf);
}
BigDecimal val =(BigDecimal) maptemp.get(colNames[j]);
jxl.write.Number labelNF = new jxl.write.Number(j, rowNum, val.doubleValue(), wcf); // 格式化数值
sheet.addCell(labelNF);
} else {
// 否则按照字符串文本格式来处理
sheet.addCell(new Label(j, rowNum, StringDateUtil.obj2Str(maptemp.get(colNames[j]))));
}
}
另外,通过网上找到的解决方法,是修改jxl源码包的 最大格式记录数限制:
private static final int maxFormatRecordsIndex = Integer.MAX_VALUE;
这实际上是非常脑残的做法,非常不推荐!
在实际生成excel文件时,需要根据需求,把单元格格式梳理清楚,一共有几种、然后,为每一种格式做一个format标识,这样,只要创建少数的格式对象即可,完全没有必要为每个单元格去单独创建一套格式。