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

时间:2009-03-09 03:06:15

标签: java excel apache-poi

刚看到崩溃,因为我们超过了255列。也许这个问题应该直接转向POI,但是我可以说我不想打扰他们,以便进一步开发它已经具有的增长性的API。 ;-) limitations page不会逐渐详细。

那么:假设输出在Excel中可读,您对实际限制的体验是什么?是否有人使用POI进行基准测试和探索软和POI生成的Excel文件的硬性限制?

我可以在POI界面中快速找到的唯一限制如下。 Microsoft列出了further limitations for Excel,似乎没有在POI中涵盖。

编辑:哎呀。刚刚意识到我们在过去的5年里没有更新过POI,所以下面的代码可能已经被替换了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.");
  }
}

7 个答案:

答案 0 :(得分:6)

Marliese,我对poi框架中的这个错误感到恼火,并且理解我需要一个styleManager。这些帖子让我觉得所有工作都已完成,直到我得出与你相同的结论。我不想重新发明轮子,所以我下载了他的框架的源代码并搜索了CellStyleManager.setCellStyle()的用法。事实是,在代码中,创建了两个初始HSSFCellStyle对象,defaultCellStyle和cellStyle。任何时候自定义样式使用cellStyle,然后使用CellStyleManager设置它。如果样式存在,则重用它,如果不存在,则创建它。任何其他尝试自定义另一种样式的尝试都是从使用CellStyleHelper的函数和defaultCellStyle重置cellStyle开始,该函数不受所有程序的影响。所以最终你会得到两个超出真实需要的样式,但到目前为止比使用另一个api更好。

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

更改基本上是,管理器知道工作簿,提供样式对象,并实现CellStyleHelper的代码。 (它们不太通用,因为管理器需要知道工作簿,总的来说,因为你必须只使用一次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种风格限制男人,这是否足够?

答案 1 :(得分:3)

关于工作簿中HSSFCellStyles数量的限制,我发现了一种比构建样式管理器更简单的方法。 POI CellUtils类有一个setCellStyleProperty()方法,它将尝试在工作簿中查找样式并使用它,或者如果它不存在则创建它。

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

   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()的主要警告是你一次只能设置一个属性。您可以轻松地重写它以获取属性和值列表。

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

答案 2 :(得分:2)

我发现POI用于编写Excel文件的最大限制之一是它在将整个文件内容写入文件之前将其保留在内存中。对于非常大的文件(许多行),这成为一个真正的问题,导致频繁的OutOfMemory异常。

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

答案 3 :(得分:1)

另一个严重的限制(我认为没有很好地解释)是HSSFCellStyle限制在工作簿中(我认为这是一个excel限制)。

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

因此,您必须管理HSSFCellStyle的内部缓存,例如:CellStyleCacheManager

答案 4 :(得分:1)

关于你的CellStyleCacheManager的paulgreg: 虽然这是一种重用样式的方法,但是你的setCellStyle()方法需要一个HSSFCellStyle参数,创建HSSFCellStyle的唯一方法是通过调用它的createCellStyle()方法将其注册到工作簿。

虽然单元格实际上使用较少的样式,但是最终是否与没有缓存的工作簿中注册的样式数量相同?或者在HSSF中是否存在某些我未注意到的未使用样式的清除?

答案 5 :(得分:1)

@albfan

我喜欢你的缓存类并将它们转换为.NET。我想我发现了一个bug。

在getGeneralStyle()中调用copyCellStyle(workbook,cellStyle,defaultValuesCellStyle);.此调用将cellStyle对象中的值复制到defaultValuesCellStyle中,从而覆盖默认值。

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

答案 6 :(得分:0)

真的看起来有点奇怪,但是我使用代码的方式我不需要hashCode所以,我把代码放在那里。我认为这是paulgreg已经开始但尚未完成的事情。