使用POI创buildExcel工作簿时有哪些(陷阱和)限制?

刚刚看到一个崩溃,因为我们超过了255列。 也许这个问题应该直接进入POI,但是可以说我不想打扰他们努力进一步开发已经非常有用的API。 😉 限制页面不是一成不变的。

所以:假设输出在Excel中可读,你有什么实际的限制? 有没有人使用POI进行基准testing,探索POI生成的Excel文件的软硬限制?

我可以在POI界面中快速find的唯一限制如下。 微软列出了似乎没有在POI中涵盖的Excel的进一步限制 。

编辑:哎呀。 刚刚意识到我们过去5年没有刷新POI,所以下面的代码可能已经被replace了100次以上。

编辑:自那时以来,2008年10月19日的版本3.2以下的代码没有改变。

/** * @throws RuntimeException if the bounds are exceeded. */ private void checkBounds(int cellNum) { if (cellNum > 255) { throw new RuntimeException("You cannot have more than 255 columns "+ "in a given row (IV). Because Excel can't handle it"); } else if (cellNum < 0) { throw new RuntimeException("You cannot reference columns with an index of less then 0."); } } 

Marliese,我在poi框架中被这个错误困扰,并且明白我需要一个styleManager。 这些post让我觉得所有的工作都完成了,直到我得出和你一样的结论。 我不想重新发明轮子,所以我下载他的框架的来源,并searchCellStyleManager.setCellStyle()的使用。 事实上,在代码中,创build了两个初始的HSSFCellStyle对象,defaultCellStyle和cellStyle。 任何时候你自定义样式使用cellStyle,然后用CellStyleManager进行设置。 如果样式存在,则重用,否则创build。 任何其他尝试自定义另一种风格开始于使用CellStyleHelper的函数和defaultCellStyle的cellStyle的重置,这是所有程序保持不变的。 所以最终你会得到两个真正需要的样式,但比使用另一个API要好得多。

正如paulgreg所说,代码遍布整个框架,但是我只需要两个类就可以join所有的代码。 我把它们留在这里,直到我写信给paulgreg,poi开发团队把它整合到它的jar中,因为我认为对于在excel中写入的未知数据,你需要这种types的pipe理器。

基本上这些变化是pipe理员知道工作簿,提供样式对象,并且实现了CellStyleHelper的代码。 (它们不是一般的,因为pipe理者需要知道工作簿,总的来说,因为你只能使用一次getGeneralStyle的调用(因为它是同一个对象,它在任何调用中被重置,但是对于一般的使用是代码那适合)所以使用它:

 ... Creates a workbook CellStyleManager styleManager = new CellStyleManager(workbook); ... Create a cell HSSFCellStyle style = styleManager.getGeneralStyle(); styleManager.setCellStyle(cell, style); // no more 4000 styles error! 

代码:感谢PaulGreg!

 // CellStyleCacheManager.java public class CellStyleCacheManager { protected Set cellStyles; protected HSSFCellStyle cellStyle; protected HSSFCellStyle defaultValuesCellStyle; protected HSSFWorkbook workbook; public CellStyleCacheManager(HSSFWorkbook workbook) { this.workbook = workbook; this.cellStyles = new HashSet(); // El desperdicio de estilos será pués de dos cellStyle = workbook.createCellStyle(); // Estilo almacenado para reiniciar el que se va a usar defaultValuesCellStyle = workbook.createCellStyle(); } /** Si el estilo se crea con createCellStyle, ya no podremos hacer nada */ public void setCellStyle(HSSFCell cell, HSSFCellStyle cellStyle) { CellStyleWrapper cellStyleWrp = new CellStyleWrapper(cellStyle); CellStyleWrapper cachedCellStyleWrp = null; Iterator it = cellStyles.iterator(); while(it.hasNext() && (cachedCellStyleWrp == null)) { CellStyleWrapper tmpCachedCellStyleWrp = (CellStyleWrapper) it.next(); if(tmpCachedCellStyleWrp.equals(cellStyleWrp)) { // Si algún estilo coincide con el actual usamos ese cachedCellStyleWrp = tmpCachedCellStyleWrp; } } if(cachedCellStyleWrp == null) { // Si el estilo no existe creamos uno nuevo HSSFCellStyle newCellStyle = workbook.createCellStyle(); CellStyleCacheManager.copyCellStyle(workbook, cellStyle, newCellStyle); CellStyleWrapper newWrp = new CellStyleWrapper(newCellStyle); cellStyles.add(newWrp); cachedCellStyleWrp = newWrp; } cell.setCellStyle(cachedCellStyleWrp.getHSSFCellStyle()); } public HSSFCellStyle getGeneralStyle() { copyCellStyle(workbook, cellStyle, defaultValuesCellStyle); return cellStyle; } public static void copyCellStyle(HSSFWorkbook wb, HSSFCellStyle c1, HSSFCellStyle c2) { c2.setAlignment(c1.getAlignment()); c2.setBorderBottom(c1.getBorderBottom()); c2.setBorderLeft(c1.getBorderLeft()); c2.setBorderRight(c1.getBorderRight()); c2.setBorderTop(c1.getBorderTop()); c2.setBottomBorderColor(c1.getBottomBorderColor()); c2.setDataFormat(c1.getDataFormat()); c2.setFillBackgroundColor(c1.getFillBackgroundColor()); c2.setFillForegroundColor(c1.getFillForegroundColor()); c2.setFillPattern(c1.getFillPattern()); try { c2.setFont(wb.getFontAt(c1.getFontIndex())); } catch(NullPointerException e) { TLogger.getInstance().log(e.getMessage()); } catch(ArrayIndexOutOfBoundsException e) { TLogger.getInstance().log("Be sure to have intialized all POI font objects !\n%s",e.getMessage()); } c2.setHidden(c1.getHidden()); c2.setIndention(c1.getIndention()); c2.setLeftBorderColor(c1.getLeftBorderColor()); c2.setLocked(c1.getLocked()); c2.setRightBorderColor(c1.getRightBorderColor()); c2.setRotation(c1.getRotation()); c2.setTopBorderColor(c1.getTopBorderColor()); c2.setVerticalAlignment(c1.getVerticalAlignment()); c2.setWrapText(c1.getWrapText()); } } CellStyleWrapper.java public class CellStyleWrapper implements Comparable { private HSSFCellStyle cs; private int hashCode; public CellStyleWrapper(HSSFCellStyle cs) { this.cs = cs; } public boolean equals(Object obj) { CellStyleWrapper csWrp_; HSSFCellStyle cs_; try { csWrp_ = (CellStyleWrapper) obj; } catch(ClassCastException e) { return false; } cs_ = csWrp_.getHSSFCellStyle(); return (cs.getAlignment() == cs_.getAlignment()) && (cs.getBorderBottom() == cs_.getBorderBottom()) && (cs.getBorderLeft() == cs_.getBorderLeft()) && (cs.getBorderRight() == cs_.getBorderRight()) && (cs.getBorderTop() == cs_.getBorderTop()) && (cs.getBottomBorderColor() == cs_.getBottomBorderColor()) && (cs.getDataFormat() == cs_.getDataFormat()) && (cs.getFillBackgroundColor() == cs_.getFillBackgroundColor()) && (cs.getFillForegroundColor() == cs_.getFillForegroundColor()) && (cs.getFillPattern() == cs_.getFillPattern()) && (cs.getFontIndex() == cs_.getFontIndex()) && (cs.getHidden() == cs_.getHidden()) && (cs.getIndention() == cs_.getIndention()) && (cs.getLeftBorderColor() == cs_.getLeftBorderColor()) && (cs.getLocked() == cs_.getLocked()) && (cs.getRightBorderColor() == cs_.getRightBorderColor()) && (cs.getRotation() == cs_.getRotation()) && (cs.getTopBorderColor() == cs_.getTopBorderColor()) && (cs.getVerticalAlignment() == cs_.getVerticalAlignment()) && (cs.getWrapText() == cs_.getWrapText()); } private int v(int i) { if(i == 0) { return 1; } else { return i; } } public int hashCode() { if(hashCode == 0) { hashCode = 17; hashCode = 37 * v(cs.getBorderBottom()); hashCode = 37 * v(cs.getBorderLeft()); hashCode = 37 * v(cs.getBorderRight()); hashCode = 37 * v(cs.getBorderTop()); hashCode = 37 * v(cs.getBottomBorderColor()); hashCode = 37 * v(cs.getDataFormat()); hashCode = 37 * v(cs.getFillBackgroundColor()); hashCode = 37 * v(cs.getFillForegroundColor()); hashCode = 37 * v(cs.getFillPattern()); hashCode = 37 * v(cs.getFontIndex()); hashCode = 37 * (cs.getHidden() ? 1 : (-1)); hashCode = 37 * v(cs.getIndention()); hashCode = 37 * v(cs.getLeftBorderColor()); hashCode = 37 * (cs.getLocked() ? 1 : (-1)); hashCode = 37 * v(cs.getRightBorderColor()); hashCode = 37 * v(cs.getRotation()); hashCode = 37 * v(cs.getTopBorderColor()); hashCode = 37 * v(cs.getVerticalAlignment()); hashCode = 37 * (cs.getWrapText() ? 1 : (-1)); } return hashCode; } public int compareTo(Object obj) { int diff = 0; CellStyleWrapper csWrp_; HSSFCellStyle cs_; try { csWrp_ = (CellStyleWrapper) obj; } catch(ClassCastException e) { return -1; } cs_ = csWrp_.getHSSFCellStyle(); diff = cs.getAlignment() - cs_.getAlignment(); if(diff != 0) { return diff; } diff = cs.getBorderBottom() - cs_.getBorderBottom(); if(diff != 0) { return diff; } diff = cs.getBorderLeft() - cs_.getBorderLeft(); if(diff != 0) { return diff; } diff = cs.getBorderRight() - cs_.getBorderRight(); if(diff != 0) { return diff; } diff = cs.getBorderTop() - cs_.getBorderTop(); if(diff != 0) { return diff; } diff = cs.getBottomBorderColor() - cs_.getBottomBorderColor(); if(diff != 0) { return diff; } diff = cs.getDataFormat() - cs_.getDataFormat(); if(diff != 0) { return diff; } diff = cs.getFillBackgroundColor() - cs_.getFillBackgroundColor(); if(diff != 0) { return diff; } diff = cs.getFillForegroundColor() - cs_.getFillForegroundColor(); if(diff != 0) { return diff; } diff = cs.getFillPattern() - cs_.getFillPattern(); if(diff != 0) { return diff; } diff = cs.getFontIndex() - cs_.getFontIndex(); if(diff != 0) { return diff; } if(cs.getHidden() != cs_.getHidden()) { return -1; } diff = cs.getIndention() - cs_.getIndention(); if(diff != 0) { return diff; } diff = cs.getLeftBorderColor() - cs_.getLeftBorderColor(); if(diff != 0) { return diff; } if(cs.getLocked() != cs_.getLocked()) { return -1; } diff = cs.getRightBorderColor() - cs_.getRightBorderColor(); if(diff != 0) { return diff; } diff = cs.getRotation() - cs_.getRotation(); if(diff != 0) { return diff; } diff = cs.getTopBorderColor() - cs_.getTopBorderColor(); if(diff != 0) { return diff; } diff = cs.getVerticalAlignment() - cs_.getVerticalAlignment(); if(diff != 0) { return diff; } if(cs.getWrapText() != cs_.getWrapText()) { return -1; } return 0; } public HSSFCellStyle getHSSFCellStyle() { return cs; } } 

有趣的是,在poi来源中,在HSSFCellStyle的评论中,来到这个条目

 // Why would you do that?? protected HSSFCellStyle(... 

4000款限制男人,是不是有足够的理由?

关于工作簿中HSSFCellStyles数量的限制,我发现比构build一个样式pipe理器更简单。 POI CellUtils类有一个setCellStyleProperty()方法,它将尝试在工作簿中查找样式,并使用它或在不存在的情况下创build它。

此示例使用POI 3.7来编写date,并且每个date单元格只使用一种格式(如果基础单元格都具有相同的样式):

  public void writeFormattedDate(Workbook wb, Cell cell, Date date) { CellUtil.setCellStyleProperty(cell, wb, CellUtil.DATA_FORMAT, wb.getCreationHelper().createDataFormat().getFormat("dd-MMM-yyyy")); cell.setCellValue(date) } 

setCellStyleProperty()的主要注意事项是一次只能设置一个属性。 您可以轻松地重写它以获取属性和值列表。

在我的testing中,限制似乎大约是4030个样式,然后在打开工作簿时会引发错误并删除多余的格式。

使用POI编写Excel文件时遇到的最大限制之一是在写入文件之前将整个文件内容保存在内存中。 对于非常大的文件(很多行),这成为一个真正的问题,导致频繁的OutOfMemoryexception。

然而,像你一样,这是一个非常旧的版本的POI。 我不确定更新版本是否更有效地使用内存。

另一个严重的限制(在我看来不是很好的解释)是HSSFCellStyle在工作簿中是有限的(我认为这是一个Excel的限制)。

你不应该在每个单元格上创build一个新的样式(因为那样,excel将无法打开你的工作簿),但是当单元格样式相似时,你必须保留对它们的引用并重新应用它们。

所以,你必须pipe理一个HSSFCellStyle的内部caching,就像这个例子: CellStyleCacheManager 。

在paulgreg有关你的CellStyleCacheManager:尽pipe这是真的,这是一种重用样式的方法,你的setCellStyle()方法需要一个HSSFCellStyle参数,而我所知道的创buildHSSFCellStyle的唯一方法就是通过调用工作簿这是createCellStyle()方法。

虽然单元格实际上使用较less的样式,但是不要使用与caching一样的工作簿中注册的相同数量的样式? 还是有没有清除HSSF中未使用的风格,我不知道?

@albfan

我喜欢你的caching类,并将其转换为.NET。 我想我发现了一个错误。

在getGeneralStyle()中有一个调用copyCellStyle(工作簿,cellStyle,defaultValuesCellStyle);. 该调用将cellStyle对象的值复制到defaultValuesCellStyle中,从而覆盖默认值。

我认为我们想要相反,所以它应该改为:copyCellStyle(workbook,defaultValuesCellStyle,cellStyle);

真的这似乎有点奇怪,但是我使用代码的方式我不需要hashCode,所以我把代码留在那里。 我认为这是paulgreg已经开始,但还没有完成。