为什么Apache poi的Workbook.close()方法将内容写入输入文件?

时间:2018-03-02 16:24:56

标签: java excel apache-poi

Apache poi的文档(版本3.17)说

  

void close()

     

抛出java.io.IOException

     

关闭从中读取工作簿的基础输入资源(文件或流)。

我的代码从模板文件创建工作簿,对其执行某些操作并将其写入新文件。模板文件应保持不变。但是当我调用close()方法时,文件的更改方式与输出文件相同。

有人可以解释一下吗?在close()方法中是否有类似内置的write()调用?这是一个错误还是一个功能?

到目前为止,我的解决方案是放弃close()调用,但不知何故感觉不完整。

    String inPath = "/home/elmicha/test/template.xlsx";
    String outPath = "/home/elmicha/test/out.xlsx";

    try {
        Workbook xlsxFile = WorkbookFactory.create(new File(inPath));

        xlsxFile.getSheetAt(0).createRow(0).createCell(0).setCellValue("test");

        try (FileOutputStream pOuts = new FileOutputStream(outPath)) {
            xlsxFile.write(pOuts);

        xlsxFile.close();

        }

    } catch (IOException | InvalidFormatException | EncryptedDocumentException ex) {
        //...
    }

2 个答案:

答案 0 :(得分:3)

这很不寻常。我不明白为什么要写模板文件。这当然不是我的经历。你可以尝试:

  • 使用FileInputStream代替File,无法写入模板文件。
  • 使用try-with-resources自动关闭Workbook

以下是一个例子:

String inPath = "/home/elmicha/test/template.xlsx";
String outPath = "/home/elmicha/test/out.xlsx";

try (Workbook xlsxFile = WorkbookFactory.create(new FileInputStream(inPath))) {
    xlsxFile.getSheetAt(0).createRow(0).createCell(0).setCellValue("test");

    try (FileOutputStream pOuts = new FileOutputStream(outPath)) {
        xlsxFile.write(pOuts);
    }

} catch (IOException | InvalidFormatException | EncryptedDocumentException ex) {
    //...
}

或者也许:

String inPath = "/home/elmicha/test/template.xlsx";
String outPath = "/home/elmicha/test/out.xlsx";

try (Workbook xlsxFile = WorkbookFactory.create(new FileInputStream(inPath));
    FileOutputStream pOuts = new FileOutputStream(outPath)) {

    xlsxFile.getSheetAt(0).createRow(0).createCell(0).setCellValue("test");
    xlsxFile.write(pOuts);


} catch (IOException | InvalidFormatException | EncryptedDocumentException ex) {
    //...
}

答案 1 :(得分:0)

"解决方案"使模板文件只读是只有在我们忽略由FileNotFoundException...(permission denied)引起的POIXMLDocument.close时才能工作。我们应该在处理后将文件设置为可写,以便进一步使用。

以下内容将起作用:

import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;

class ReadAndWriteExcelWorkbook {

 public static void main(String[] args) throws Exception {

  File templatefile = new File("file.xlsx");

  templatefile.setWritable(true);
  try (Workbook workbook = WorkbookFactory.create(templatefile)) { //at this point the file must be writable
  //try (Workbook workbook = WorkbookFactory.create(templatefile, null, true)) { //this will not work

   Sheet sheet = workbook.getSheetAt(0);

   for (int r = 0; r < 10; r++) {
    Row row = sheet.getRow(r);
    if (row == null) row = sheet.createRow(r);
    Cell cell = row.getCell(r);
    if (cell == null) cell = row.createCell(r);
    cell.setCellValue("changed");
   }

   FileOutputStream out = new FileOutputStream("fileNew.xlsx");
   workbook.write(out);
   out.close();

   templatefile.setWritable(false);

  } catch (java.io.FileNotFoundException ioex) {
   ioex.printStackTrace(); //we simply do ignoring this FileNotFoundException
  }

  templatefile.setWritable(true);

 }
}

注意:

虽然WorkbookFactory.create(templatefile) templatefile必须是可写的,因为默认为WorkbookFactory.createboolean readOnly设置为false。因此,如果此时templatefile设置为只读,则WorkbookFactory.create(templatefile)将失败。

我们无法使用WorkbookFactory.create(templatefile, null, true) - 将boolean readOnly设置为true - 因为在workbook.write POIXMLDocument.write同时将更改提交到底层{{}}时会失败{ {1}}。