3

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

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

我可以在 POI 界面中快速找到的唯一限制如下。Microsoft 列出了 POI 中似乎未涵盖的 Excel 的进一步限制。

编辑:哎呀。刚刚意识到我们在过去 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.");
  }
}
4

7 回答 7

6

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

正如 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种款式限制男人,够不够理由?

于 2009-07-25T21:10:22.037 回答
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 种样式,然后在打开工作簿时会引发错误并删除多余的格式。

于 2011-02-01T05:37:49.323 回答
2

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

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

于 2009-03-09T03:38:39.063 回答
1

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

尽管单元格实际上使用了较少的样式,但您最终在工作簿中注册的样式数量与没有缓存的情况相同吗?或者是否有某种我不知道的清除 HSSF 中未使用的样式?

于 2009-04-30T13:39:59.090 回答
1

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

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

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

于 2009-03-19T14:48:52.433 回答
1

@albfan

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

里面有getGeneralStyle()一个电话:

copyCellStyle(workbook, cellStyle, defaultValuesCellStyle);

此调用将 cellStyle 对象中的值复制到 defaultValuesCellStyle 中,从而覆盖默认值。

我认为我们想要相反的,所以它应该改为:

copyCellStyle(workbook, defaultValuesCellStyle, cellStyle);
于 2009-08-26T09:06:37.430 回答
0

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

于 2009-07-27T09:41:30.793 回答