添加大型查询时,如何修复SpreadSheetAddRows函数崩溃?

时间:2012-12-17 20:35:14

标签: java arrays coldfusion apache-poi coldfusion-9

EDIT3:感谢@Leigh的帮助,我将问题缩小到了查询中的日期列。使用原始代码集和POI时,当SpreadSheetAddRows()尝试添加包含类似日期的单元格的非常大的查询时,页面崩溃。我在这里做了一个错误报告:https://bugbase.adobe.com/index.cfm?event=bug&id=3432184


我有一个查询,我要添加到一个spreadhseet对象,当查询有一个非常多的行(本例中为18583)时,该对象似乎是错误的。确切的错误如下:

java.lang.ArrayIndexOutOfBoundsException: -32735
at java.util.ArrayList.get(ArrayList.java:324)
at org.apache.poi.hssf.model.WorkbookRecordList.get(WorkbookRecordList.j ava:50)
at org.apache.poi.hssf.model.Workbook.getExFormatAt(Workbook.java:787)
at org.apache.poi.hssf.usermodel.HSSFCell.getCellStyle(HSSFCell.java:901 )
at org.apache.poi.hssf.usermodel.HSSFSheet.autoSizeColumn(HSSFSheet.java :1727)
at coldfusion.excel.Excel.autoResize(Excel.java:1246)
at coldfusion.excel.Excel.autoResize(Excel.java:1240)
at coldfusion.excel.Excel.addRows(Excel.java:1214)
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7089) at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7076)

以下是相关代码:

<cfset xls = spreadsheetNew()>
<cfset spreadsheetAddRow(xls, arrayToList( qryTest.getMeta().getColumnLabels() ))>
<cfset SpreadsheetFormatRow(xls, {bold=true,fgcolor="brown",color="white"}, 1)>
<cfset SpreadsheetAddRows(xls, qryTest)>
<cfheader name="Content-Disposition" value="attachment; filename=#filename#">
<cfcontent variable="#spreadsheetReadBinary(xls)#" reset="yes" type="application/vnd.ms-excel">

编辑:我以前成功使用过cfspreadsheet,但它没有生成带有标题的电子表格(并且还有需要创建临时文件以供服务的缺点。)


EDIT2:关注@Leigh建议我更新了CF9 / lib文件夹中的POI。现在错误已更改为以下内容:

<cfset SpreadsheetFormatRow(xls, {bold=true,fgcolor="brown",color="white"}, 1)>给出以下消息:org.apache.poi.hssf.util.HSSFColor.getIndexHash()Ljava / util / Hashtable;

错误代码:

java.lang.NoSuchMethodError:
org.apache.poi.hssf.util.HSSFColor.getIndexHash()Ljava/util/Hashtable;
at coldfusion.excel.Excel.getHSSFColor(Excel.java:2094)
at coldfusion.excel.Excel.findFont(Excel.java:2237)
at coldfusion.excel.Excel.getCellStyle(Excel.java:2318)
at coldfusion.excel.Excel.formatRow(Excel.java:2948)
at coldfusion.excel.Excel.formatRow(Excel.java:2963)
at coldfusion.excel.Excel.formatRow(Excel.java:2981)
at coldfusion.runtime.CFPage.SpreadSheetFormatRow(CFPage.java:7268)

评论该行,它现在再次崩溃: <cfset SpreadsheetAddRows(xls, qryTest)>

错误代码:

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:1120) 
at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:73) 
at coldfusion.excel.Excel.addRow(Excel.java:1323)
at coldfusion.excel.Excel.addRows(Excel.java:1203) 
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7089) 
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7076) 

4 个答案:

答案 0 :(得分:3)

我怀疑它与CF或JRE版本完全无关。至少不是直接的。这听起来像是POI中的一个错误。

如果查看异常,它会清楚地显示当CF调用尝试自动调整列大小的POI方法时(在添加查询数据之后),会出现问题。快速搜索发现了一些与ArrayIndexOutOfBoundsException like this one发生类似HSSFSheet.autoSizeColumn错误的报告(恰好提及ColdFusion):

  

如果您尝试使用org.apache.poi.hssf.usermodel.HSSFSheet和   设置超过32767后,在列上的方法autosizecolumn(int)   然后抛出ArrayOutOfBoundsException。

根据错误报告,问题存在于3.5版本中,这是ColdFusion 9中包含的相同(主要)版本。其中一位POI开发人员表示该问题已在更高版本中得到修复。所以你可以尝试更新POI jar。除此之外,如果您可以组合一个再现问题的测试用例,您可能需要提交bug report

  

我之前使用cfspreadsheet成功,但事实并非如此   生成一个带标题的电子表格(它也有一个缺点   需要创建一个临时文件来服务。)

cfspreadsheet可能不会尝试像spreadsheetAddRows那样自动调整列的大小,因此不会发生错误。所以明显的解决方法(而不是一个很好的解决方法)是避免尝试调整列宽的函数。

答案 1 :(得分:1)

如果您退出代码并检查错误,则会获得this from the java documentationhere is another reference

  

抛出以指示已使用非法索引访问数组。索引为负数或大于或等于数组的大小。

该错误还会显示尝试的非法索引值:-32735

现在您的问题是您没有在代码中指定索引值,因为您使用的是ColdFusion函数。该函数(SpreadsheetAddRows)正在尝试将查询结果转换为数组,然后将每个值附加到Excel电子表格的行中。它正在利用底层Java运行时来执行这些任务,这就是抛出错误。所以我担心你遇到这种限制时会有点困惑。您可以尝试升级运行ColdFusion安装的JRE版本,以查看问题是否已在较新版本中得到解决。我相信ColdFusion 9附带Java 1.6.0_14 see here。由于DOS vulnerability patch,您应该至少运行1.6.0_24。它看起来高达1.6.0_38 now,但您必须检查Adobe支持。

如果升级JRE无法解决问题,那么我相信您需要更改ColdFusion代码以避免此问题。您声明使用CFSpreadSheet标记取得了成功。或者,您可以使用不同的方式将查询结果传递给SpreadsheetAddRows函数。 (虽然我假设你已经筋疲力尽了。)可能循环查询并构建自己的数组或循环查询并一次添加一行。我意识到这可能不是最佳的,但在尝试了几种不同的方式之后,人们希望能够成为最佳选择。

我还要在你的帖子中添加ColdFusion标签(没有版本号),以便更多地关注它。

<强>更新

只想跟进ColdFusion 9支持的Java版本。我发现this blog entry by Charlie Arehart讨论了Adobe对ColdFusion服务器的Java升级的立场。这链接到official Adobe post here,表示将支持任何次要版本升级。因此对于ColdFusion 9“支持所有未来的JDK 1.6.0_x版本。”

答案 2 :(得分:1)

(摘自http://poi.apache.org/spreadsheet/quick-guide.html

  

请注意,工作簿中的最大唯一字体数限制为   32767(最大正短)。你应该重新使用你的字体   应用而不是为每个单元格创建字体。例子:

     

错:

for (int i = 0; i < 10000; i++) {
    Row row = sheet.createRow(i);
    Cell cell = row.createCell((short) 0);

    CellStyle style = workbook.createCellStyle();
    Font font = workbook.createFont();
    font.setBoldweight(Font.BOLDWEIGHT_BOLD);
    style.setFont(font);
    cell.setCellStyle(style);
}
     

正确:

CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
style.setFont(font);
for (int i = 0; i < 10000; i++) {
    Row row = sheet.createRow(i);
    Cell cell = row.createCell((short) 0);
    cell.setCellStyle(style);
}

无论如何,你也可以试试这个:

org.apache.poi.hssf.usermodel.HSSFOptimiser.optimiseCellStyles(HSSFWorkbook)

答案 3 :(得分:0)

根据我对数组的经验,当你得到OutOfBounds异常时,通常是因为我“超出”了数组 - 也就是说,我比索引中的项目总数多了一个。这通常是因为我忘记了当数组以0开头时,我必须只循环到数组长度 - 1.

确保没有超过数组的长度。