Apache POI – FileInputStream работает, файл не работает (NullPointerException)

Я пытаюсь скопировать все рабочие листы из одной книги в другую книгу. Дело в том, что он нормально работает, если я читаю книги через 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 ? Я делаю что-то неправильно?

FYI: Я использую POI 3.16.

Использование File вместо FileInputStream для открытия FileInputStream Workbook приводит к уменьшению объема памяти, потому что тогда в случае XSSF ( *.xlsx ) ZipPackage будет открыт из файла *.xlsx а вместо этого будет считывать весь ZIP контент в Память.

Но это также означает, что ZipPackage открывает файл, пока Workbook не будет закрыта. Поэтому, пока Workbook не будет закрыта, ничто не сможет записать в этот файл в одно и то же время. Таким образом, поскольку нет возможности записать содержимое FileInputStream Workbook обратно в тот же файл, из которого была открыта Workbook , используя File вместо FileInputStream для открытия FileInputStream Workbook , прекрасно, если вы хотите только читать из этой Workbook . Но это не работает, если вы хотите читать и писать в один и тот же файл. Затем FileInputStream и FileOutputStream .

Поэтому в вашем случае вы 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); oldWB.close(); newWB.close(); 

должно сработать.

Btw .: Если вы используете File , то вы не должны использовать FileInputStream для того же файла. Поэтому не используйте fisOld .

Другим недостатком использования File вместо FileInputStream для открытия FileInputStream Workbook является то, что при закрытии FileInputStream Workbook и поэтому неявным закрытием подстилающей файловой системы ( POIFSFileSystem в случае HSSF и ZipPackage в случае XSSF ) файл получает обновленную последнюю измененную дату. В файл не внесены изменения, но файл был открыт и записано в файловую систему. Вот почему обновленная дата обновляется.


Редактировать Sep 21 2017: Недостаток использования 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"); workbook.write(new FileOutputStream("fileNew.xlsx")); workbook.close(); } } 

После этого кода fileNew.xlsx оба файла fileNew.xlsx а также file.xlsx .

  • Как избежать NullPointerException с пустой ячейкой с помощью POI?
  • Нулевые значения в первом столбце предотвращают импорт файлов Excel в Pentaho Spoon?
  • Java | Apache POI | Как избежать исключения нулевого указателя без создания строки
  • Как исправить java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver для файла Excel?
  • Jxl NullPointerException для работы с методом workbook.close ()
  • Excel (.xlsx) не работает с использованием java
  • SUMIF с несколькими листами и одинаковым значением
  • Давайте будем гением компьютера.