【问题标题】:POI: Append rows to existing workbookPOI:将行追加到现有工作簿
【发布时间】:2013-09-13 20:22:46
【问题描述】:

使用 XSSFWorkbook,是否可以将行附加到现有工作表?我正在执行多次写入(由于错误,这是一个要解决的 PITA),虽然我可以多次写出新工作表,但我似乎无法追加。

我目前正在做的事情如下:

  1. 阅读我的工作簿的工作表。
  2. 加载工作簿。
  3. 将行追加到内存中的工作簿
  4. 再写一次。

4 似乎不起作用,完全忽略它!

我知道 SXSSFWorkbook 存在,但尝试将我现有的 XSSFWorkbook 转换为流式工作簿会在写入时造成损坏。

有没有可能解决这个难题?

更新:根据建议更改了代码,但出现流关闭错误。

代码:(物理行正确返回,但没有写出)

private void writeToSheetMultipleTimes(SXSSFWorkbook wb,
            ReportTemplateStructure appA, File wbFile)
    {

        Sheet sheet = wb.getSheetAt(0);

        log.info("Attempting multi-write to sheet: " + sheet.getSheetName());
        for(int i = 0; i < 10; i++)
        {

            Row row = sheet.getRow(i);

            if (row == null) {
               row = sheet.createRow(i);
            }
            Cell cell = row.getCell(0, Row.CREATE_NULL_AS_BLANK);



            cell.setCellValue("Written value:" + i);

            int numRows = sheet.getPhysicalNumberOfRows();

            log.info("Current row count: " + numRows);

            try{
                XSSFWorkbook xssfBook = (XSSFWorkbook)writeOutAndReadBack(wb);
                wb.dispose();

                wb = new SXSSFWorkbook(xssfBook);
            } catch (Exception e)
            {
                log.error("Unable to perform multiple write to same sheet", e);
            }
        }


    }

   public Workbook writeOutAndReadBack(Workbook wb) {
        if(!(wb instanceof SXSSFWorkbook)) {
            throw new IllegalArgumentException("Expected an instance of SXSSFWorkbook");
        }

        Workbook result;
        try {
            FileOutputStream baos = new FileOutputStream(streamingWorkBookFile);
            wb.write(baos);
            InputStream is = new FileInputStream(streamingWorkBookFile);
            result = new XSSFWorkbook(is);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result;
    }  

【问题讨论】:

  • POI 附带了大量的单元测试,这些测试按照您的描述进行,并且全部通过而没有问题!我建议您发布一些代码来显示您在做什么,以便我们可以尝试发现您的错误
  • OK 刚刚用代码编辑了它。谢谢!
  • 您使用的是什么操作系统? Windows 因对您不小心读取和写入同一个文件而感到不满而臭名昭著。如果你写到不同的文件,它会工作吗?
  • 我在 Windows 上,是的。我认为这是 POI。由于我在上面有一个测试方法,可以打开工作簿并在每次后续运行时添加一张工作表 - 但是当我尝试写入同一张工作表时,它突然爆炸了。然而,在这两种方法中我都在写/打开 - 那么有什么区别?虽然我必须说,在第一种方法中,我使用 SXSSFWorkbook。

标签: apache-poi


【解决方案1】:

您似乎总是对工作表 0 进行更改,但您每次都调用 createRow。如果那里已经有东西,例如在您的第二次通过时,这将不会顺利!您要么每次都需要添加一个新工作表,要么首先通过调用getRow(int) 来检查行是否存在,并且仅在它为空时创建。

如果我们查看您的代码 sn-p:

Sheet sheet = wb.getSheetAt(0);
for(int i = 0; i < 10; i++)
{
    Row row = sheet.createRow(i);
    Cell cell = row.createCell(0);

应该是这样的:

Sheet sheet = wb.createSheet();
for(int i = 0; i < 10; i++)
{
    Row row = sheet.createRow(i);
    Cell cell = row.createCell(0);

或者您应该先检查并仅创建缺少的行/单元格,例如

Sheet sheet = wb.getSheetAt(0);
for(int i = 0; i < 10; i++)
{
    Row row = sheet.getRow(i);
    if (row == null) {
       row = sheet.createRow(i);
    }
    Cell cell = row.getCell(0, Row.CREATE_NULL_AS_BLANK);

【讨论】:

  • 我也看不出第一块和第二块之间的区别。我实现的第三个块,没用。创建了,但没有写出来。
  • 你认为这与它有什么关系吗?无论如何,我第二次尝试乱写,我得到流关闭错误。也许我写得不对。 issues.apache.org/bugzilla/show_bug.cgi?id=53515
  • 我建议您查看加载文件的众多 POI 单元测试之一,进行一些更改并再次将它们写回。将它们与您的代码进行比较,看看您做错了什么。我的答案中所有 3 个代码 sn-ps 之间存在关键区别,答案试图解释它们!
  • 堵嘴,所以在第二个 sn-p 中,我看到您正在创建一个新工作表,但我不能这样做。我必须附加。我已经提取了 POI 单元测试并正在查看以下内容:TestSXSSFWorkbook.testAddToExistingWorkbook() - 他们基本上和我做同样的事情。唯一的区别是,当他们写出/读回时,它使用的是 BOS 而不是 FOS。由于它们实际上并没有将任何内容写入磁盘,我们如何确定实际文件正在正确创建。我觉得我看到了不同的东西..不是吗?
  • 您只能追加到不存在的行! TestSXSSFWorkbook.testAddToExistingWorkbook() 仅起作用,因为它附加的行以前尚未创建。您可以将该测试更改为写入临时文件,您应该会看到它继续正常工作
【解决方案2】:

您可以使用XSSFSheet 类中的getPhysicalNumberOfRows() 方法来获取最后更新的行号。现在通过增加这个值来创建一个新行来追加新数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    相关资源
    最近更新 更多