当前位置: 首页 > 知识库问答 >
问题:

Apache POI-FileInputStream工作,文件对象失败(NullPointerException)

燕钟展
2023-03-14

我尝试将所有工作表从一个工作簿复制到另一个工作簿。问题是,如果我通过FileInputStreams阅读工作簿,它可以正常工作,但不适用于文件对象。

考虑以下方法:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataConsolidateFunction;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFPivotTable;
import org.apache.poi.xssf.usermodel.XSSFSheet;


public void copyAllSheetsAcrossWorkbook(String oldWorkbook, String newWorkbook)
        throws EncryptedDocumentException, InvalidFormatException, IOException {
    FileInputStream fisOld = null;
    FileInputStream fisNew = null;
    Workbook oldWB = null;
    Workbook newWB = null;
    FileOutputStream fileOut = null;

    System.out.println("oldWorkbook: " + oldWorkbook);
    System.out.println("newWorkbook: " + newWorkbook);
    fisOld = new FileInputStream(oldWorkbook);
    fisNew = new FileInputStream(newWorkbook);

    // THIS WORKS
    // oldWB = WorkbookFactory.create(fisOld);
    // newWB = WorkbookFactory.create(fisNew);

    // THIS DOES NOT WORK
    oldWB = WorkbookFactory.create(new File(oldWorkbook));
    newWB = WorkbookFactory.create(new File(newWorkbook));

    if (newWB == null) {
        System.out.println("newWB is null");
    }
    // CellStyle newStyle = newWB.createCellStyle();
    Row row;
    Cell cell;
    copiedSheets = new ArrayList<String>();
    for (int i = 0; i < oldWB.getNumberOfSheets(); i++) {
        XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i);
        String sheetNameFromOldWB = sheetFromOldWB.getSheetName();
        XSSFSheet sheetForNewWB = (XSSFSheet) newWB.getSheet(sheetNameFromOldWB);
        if (sheetForNewWB != null) {
            int sheetIndex = newWB.getSheetIndex(sheetNameFromOldWB);
            newWB.removeSheetAt(sheetIndex);
        }
        LOGGER.info("Copying to new Workbook: " + sheetNameFromOldWB);
        sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName());
        for (int rowIndex = 0; rowIndex < sheetFromOldWB.getPhysicalNumberOfRows(); rowIndex++) {
            row = sheetForNewWB.createRow(rowIndex);
            for (int colIndex = 0; colIndex < sheetFromOldWB.getRow(rowIndex).getPhysicalNumberOfCells(); colIndex++) {
                cell = row.createCell(colIndex);
                // get cell from old WB's sheet and when cell is null, return as blank cells.
                Cell c = sheetFromOldWB.getRow(rowIndex).getCell(colIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);

                // Below is where all the copying is happening.
                // CellStyle origStyle = c.getCellStyle();
                // newStyle.cloneStyleFrom(origStyle);
                // cell.setCellStyle(newStyle);
                switch (c.getCellTypeEnum()) {
                case STRING:
                    cell.setCellValue(c.getRichStringCellValue().getString());
                    break;
                case NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        cell.setCellValue(c.getDateCellValue());
                    } else {
                        cell.setCellValue(c.getNumericCellValue());
                    }
                    break;
                case BOOLEAN:
                    cell.setCellValue(c.getBooleanCellValue());
                    break;
                case FORMULA:
                    cell.setCellFormula(c.getCellFormula());
                    break;
                default:
                    break;
                }
            }
        }
        copiedSheets.add(oldWB.getSheetName(i));

    }
    fileOut = new FileOutputStream(newWorkbook);
    newWB.write(fileOut); // <------ HERE I GET NULLPOINTEREXCEPTION
    fisOld.close();
    fisNew.close();
    oldWB.close();
    fileOut.close();
    newWB.close();

我得到以下异常在newWB.↑(fileOut);

Exception in thread "main" org.apache.poi.POIXMLException: java.lang.NullPointerException
at org.apache.poi.POIXMLDocument.getProperties(POIXMLDocument.java:168)
at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:246)
at com.capgemini.toolkit.App.copyAllSheetsAcrossWorkbook(App.java:263)
at com.capgemini.toolkit.App.main(App.java:58)

Caused by: java.lang.NullPointerException
at org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream.read(ZipSecureFile.java:210)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager$RewindableInputStream.read(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
at org.apache.poi.util.DocumentHelper.readDocument(DocumentHelper.java:140)
at org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:143)
at org.openxmlformats.schemas.officeDocument.x2006.extendedProperties.PropertiesDocument$Factory.parse(Unknown Source)
at org.apache.poi.POIXMLProperties.<init>(POIXMLProperties.java:78)
at org.apache.poi.POIXMLDocument.getProperties(POIXMLDocument.java:166)
... 3 more

在POI留档中,由于较低的内存消耗,总是提到更好地使用File对象。这就是为什么我想知道为什么它不适用于File对象。

为了进行测试,这是主方法中运行的唯一方法,我使用了两个新的Excel文件(.xlsx)和一些虚拟数据

有人知道为什么它不适用于文件对象吗?我做错什么了吗?

仅供参考:我使用的是POI 3.16。

共有2个答案

夔宏深
2023-03-14

刚刚偶然发现了这个问题的潜在解决方案。我不是专家,所以请随意建议替代或修改我的方法。

我还遇到了这个问题,其中POI留档建议使用File对象而不是FileInputStream,但没有提到创建的工作簿不能写入原始文件以修改它。

但是,通过使用nio创建原始文件的临时副本。频道。文件频道。transferFrom是后来JDK的函数(如图所示,是用Java复制文件的标准简明方法?)我能够从复制的文件中读取数据,然后使用常规工作簿写入原始文件。写函数。

需要注意的是,在访问“临时”副本时,仍然无法删除该副本。然而,它显然仍然可以传输数据。一旦jvm实例结束,文件就可以被删除,因此我将其视为有时创建的临时或备份文档,例如在修改Word文档时。

爱亮
2023-03-14

使用File而不是FileInputStream来打开Workbook会降低内存占用,因为在XSSF*. xlsx)的情况下,ZipPackage将直接从*. xlsx文件打开,而不是将整个ZIP内容读取到内存中。

但这也意味着,在Workbook关闭之前,ZipPackage将打开文件。因此,在Workbook关闭之前,没有任何东西可以同时写入该文件。因此,由于不可能将Workbook内容写回从Workbook打开的同一文件,因此使用File而不是FileInputStream打开Workbook是可以的,如果您只想从该Workbook读取内容的话。但是如果你想从同一个文件中读写,它就不起作用了。然后需要FileInputStreamFileOutputStream

因此,在您的案例中,您尝试从文件中读取工作簿newWB,然后使用

fileOut = new FileOutputStream(newWorkbook);
newWB.write(fileOut);

当文件已经打开时。失败。

但是:

   fisNew = new FileInputStream(newWorkbook);
   oldWB = WorkbookFactory.create(new File(oldWorkbook));
   newWB = WorkbookFactory.create(fisNew);
...
   fileOut = new FileOutputStream(newWorkbook);
   newWB.write(fileOut);
   fileOut.close();

   oldWB.close();
   newWB.close();

应该行得通。

顺便说一句。:如果您使用的是File,那么您不应该对同一文件使用FileInputStream。所以不要使用fisOld

使用文件而不是文件输入流打开工作簿的另一个缺点是,在关闭工作簿并隐式关闭底层文件系统时(POIFSFileSystem用于HSSFzip包用于XSSF)该文件将获得更新的上次修改日期。没有对文件进行任何更改,但该文件已被打开并写入文件系统。这就是上次修改日期被更新的原因。

2017年9月21日编辑:使用文件的缺点似乎比最初想象的要大。OPCPackage。close还将所有更改保存到参考底图OPCPackage。因此,如果您正在从一个文件中打开一个XSSFWorkbook,然后想使用write(java.io.OutputStream)将更改写入另一个文件,那么在关闭OPCPackage时,源文件也会被更改。只有在XSSFWorkbook中使用write(java.io.OutputStream)时才会出现问题。write被称为调用poimmldocumentpart的。onSave,它“保存底层OOXML包中的更改”。因此,OPCPackage在关闭前会更新所有更改。

简短的例子:

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

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

class ReadAndWriteExcelWorkbook {

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

  Workbook workbook  = WorkbookFactory.create(new File("file.xlsx"));

  Sheet sheet = workbook.getSheetAt(0);
  Row row = sheet.getRow(0);
  if (row == null) row = sheet.createRow(0);
  Cell cell = row.getCell(0);
  if (cell == null) cell = row.createCell(0);
  cell.setCellValue("changed");

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

 }
}

在此代码之后,两个文件都fileNew。xlsx以及文件。xlsx已更改。

 类似资料:
  • 问题内容: 我尝试将所有工作表从一个工作簿复制到另一工作簿。事实是,如果我通过FileInputStreams读取工作簿,它可以正常工作,但不适用于文件对象。 请考虑以下方法: 我在收到以下异常: 在POI文档中,始终会提到由于内存消耗较低而更好地使用了对象。这就是为什么我想知道为什么它不适用于对象。 为了进行测试,这是在主方法中运行的唯一方法,我使用了2个带有一些伪数据的新Excel文件(.xl

  • 问题内容: 当我尝试部署应用程序时,出现以下错误: 问题答案: 您必须在MAVEN_HOME / conf / settings.xml节服务器中验证您的凭据 id必须与pom.xml中的分发管理中的id匹配

  • 问题内容: 我有一个.Jar文件,它将在运行时将数据加载到数据库中。我已经计划通过詹金斯来担任这项工作。当我在詹金斯执行作业时,它将成功运行.JAR。但是,请说作业中是否存在空指针异常,并且该异常未成功完成。即便如此,詹金斯仍然说工作已经“通过”。如果作业执行过程中出现问题,如何使作业失败? 问题答案: @Corey的解决方案很好。而且,如果您不想编写JUnit测试并在Jenkins中提供支持,则

  • 问题内容: 我正在使用CentOS 5和Jenkins 1.430。当我尝试构建时,出现错误: 该线程似乎说Master / Slave出了点问题:https : //groups.google.com/forum/? fromgroups =#!topic /jenkinsci-issues/MaMqjK3iW8Y 但这并没有真正提供解决方案。詹金(Jenkin)奴隶表示已连接,并反映在詹金斯(

  • 问题内容: 我有这段代码: 在此代码的最后一行,我有以下错误消息: 无法从类型静态引用非静态方法。 如何改善代码并从列表中创建JavaRDD对象(实际上应该具有多个Rows对象)。目前,我不了解代码的哪一部分是静态的。 问题答案: 您只需要实例化JavaSparkContext。

  • 我正在开发一个渐进式web应用程序,目的是缓存所有离线使用的资产。这是我的服务人员 无论我是否在线,服务工作人员都无法缓存一些资产(在本例中bundle.js),并破坏了我的缓存优先系统,即使我在注册工作人员时记录了一条成功消息。 https://postimg.org/gallery/2yo1ig35y/