当前位置: 首页 > 面试题库 >

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.write(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对象。

为了进行测试,这是在主方法中运行的唯一方法,我使用了2个带有一些伪数据的新Excel文件(.xlsx)。

有谁知道为什么它不能与File对象一起使用?难道我做错了什么?

仅供参考:我正在使用POI 3.16。


问题答案:

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

但这也意味着,将ZipPackage打开文件,直到Workbook将文件关闭。因此,在Workbook将被关闭之前,无法同时写入该文件。因此,由于不可能将Workbook内容从Workbook打开时的位置写回到相同的文件,因此,如果您只想从中读取内容,则使用a
File代替FileInputStream打开a
Workbook可以Workbook。但是,如果您要读取和写入相同的文件,则无法使用。然后FileInputStreamFileOutputStream需要。

因此,在您的情况下,您尝试Workbook newWB从中读取File,然后使用将其Workbook写入同一文件

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

使用的另一个缺点File,而不是FileInputStream打开一个Workbook是同时关闭Workbook,因此隐含关闭垫层文件系统(POIFSFileSystem在的情况下,HSSFZipPackage在以下情况下XSSF)的文件中获取更新的最后修改日期。没有对文件进行任何更改,但是文件已被打开并将新的文件写入文件系统。这就是为什么上次修改日期被更新的原因。

编辑2017年9月21日:使用a的缺点File似乎比想像的要严重。OPCPackage.close还将所有更改保存到底层OPCPackage。因此,如果您XSSFWorkbook从文件中打开一个文件,然后想使用将更改内容写入另一个文件中write(java.io.OutputStream stream),则在关闭时也会更改源文件OPCPackage。仅当发生该问题 write(java.io.OutputStream stream)从用于XSSFWorkbook从那以后POIXMLDocument.write被称为它调用POIXMLDocumentPart.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以及file.xlsx都被更改。



 类似资料:
  • 我尝试将所有工作表从一个工作簿复制到另一个工作簿。问题是,如果我通过FileInputStreams阅读工作簿,它可以正常工作,但不适用于文件对象。 考虑以下方法: 我得到以下异常在: 在POI留档中,由于较低的内存消耗,总是提到更好地使用对象。这就是为什么我想知道为什么它不适用于对象。 为了进行测试,这是主方法中运行的唯一方法,我使用了两个新的Excel文件(.xlsx)和一些虚拟数据。 有人知

  • 安装失败,消息为无效文件:K:\project\app\build\中间产品\spit-apk\with_ImageProcessor\debug\slices\slice_0.apk.解决此问题的方法可能是卸载现有版本的apk(如果存在),然后重新安装。 警告:卸载将删除应用程序数据! 是否要卸载现有应用程序? 我运行我的项目在Android Studio2.3 beta 3.

  • 问题内容: 这可能很愚蠢,但是我想知道后台操作的区别。 上面两行代码之间的区别是什么,以及它们在什么情况下使用。 问题答案: extend :它是InputStream的专用版本,旨在读取文件。 根据InputStream的用途,有几种实现。 通常最好的做法是使用代码中所需的最高类型。因此,如果您的代码需要从而不是从a 读取数据,则应使用。但是,如果您确实需要保持对象的信息为a 而不只是a ,则应

  • Html树: Xpath://table[@class='ur MatrixLayout urhtmltableReset']//tr//table//tr//td//div//div/span[contains(text(),'revisations')]

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

  • 我有一个困扰了我好几天的问题。。。我检查了类似的问题,但没有找到解决方案。 我使用NetBeans IDE。我建立项目jar文件,即“Clock.jar”,其中包含一个“时钟”命名文件夹,其中发现了一些图像、文本文件和所有项目类。下面的代码创建一个图像图标工作 但是下面读取文本文件的代码失败 正如您可能猜到的那样,引发了NullPointer异常,这意味着它可能找不到文件。 但是,为什么图像图标构