Открытие документа Apache Poi Word дает исключение NullPointerException - PullRequest
0 голосов
/ 09 февраля 2019

Я написал программу, которая открывает документ Microsoft Word для чтения и записи.

Эта программа читает абзацы и таблицы Word и заменяет заполнители.После запуска программа сохраняет документ по тому же пути к файлу, что и при чтении.

Если я использую эту опцию для открытия документа, я получаю исключение NullPointerException:

String filePath = "...";
XWPFDocument doc = new XWPFDocument(OPCPackage.open(filePath));
// Replace paragraphs.
doc.write(new FileOutputStream(filePath));
doc.close();

Вотstacktrace:

java.lang.NullPointerException
    at org.apache.poi.POIXMLDocument.getProperties(POIXMLDocument.java:147)
    at org.apache.poi.POIXMLDocument.write(POIXMLDocument.java:225)
Caused by: java.lang.NullPointerException
    at org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream.read(ZipSecureFile.java:211)
    at org.apache.xerces.impl.XMLEntityManager$RewindableInputStream.readAndBuffer(Unknown Source)
    at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
    at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
    at org.apache.xerces.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:163)
    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:145)

И если я использую эту опцию:

String filePath = "...";
InputStream fis = new FileInputStream(filePath);
XWPFDocument doc = new XWPFDocument(OPCPackage.open(fis));
// Replace paragraphs.
doc.write(new FileOutputStream(filePath));
doc.close();

Работает правильно.Я пытался сохранить документ по другому пути, и эта ситуация работает правильно.

Поэтому я не понял, почему у меня появляется сообщение об ошибке при использовании метода open(String path) для открытия документа Word.

В чем разница между методами OPCPackage.open (InputStream in) и OPCPackage.open (String path)?И почему у меня есть NullPointerException?

1 Ответ

0 голосов
/ 09 февраля 2019

открытый статический открытый OPCPackage (java.io.InputStream in) сообщает:

Открыть пакет.Примечание - использует немного больше памяти, чем open (String), которому не нужно хранить весь zip-файл в памяти, и он может использовать нативные методы

Так что это значит? открытый статический открытый OPCPackage (путь java.lang.String) , а также public static OPCPackage open(java.io.File file) открывают файловую систему ZipPackage непосредственно из файла *.docx.При этом используется меньше памяти, чем public static OPCPackage open(java.io.InputStream in), что сначала считывает файловую систему ZIP в память, используя InputStream.Но, с другой стороны, файл *.docx теперь тоже открыт, и каждая попытка что-то записать в этот открытый файл должна приводить к ошибкам (несколько разных, не всегда NPE, для меня это java.io.EOFException: Unexpected end of ZLIB input stream с использованием apache poi 4.0.1 [1]) до тех пор, пока действие записи не только выполняет запись в открытую файловую систему ZIP, но и в открытый файл *.docx.

[1]: Только что протестировано, я получаю именно ваш NPE, используя apache poi 3.17 в Windows 10. Ubuntu Linux просто падает.

Вывод:

Открытие OPCPackage (ZipPackage) из File напрямую и последующая запись в другой File работает.Открытие OPCPackage из File напрямую, а затем запись в тот же File не работает.

Это верно для всех форматов файлов Office Open XML, которые обрабатываются с использованием ZipPackage в apache poi.

Чтобы получить преимущество от использования меньшего количества памяти при создании XWPFDocument из-за использования File вместо InputStream и, тем не менее, возможности записи в один и тот же файл, мы могли бы использовать временную копиюфайл выглядит следующим образом:

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

import java.nio.file.Paths;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;

public class WordReadAndReWrite {

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

  String filePath = "WordDocument.docx";
  String tmpFilePath = "~$WordDocument.docx";

  File file = Files.copy(Paths.get(filePath), Paths.get(tmpFilePath), StandardCopyOption.REPLACE_EXISTING).toFile();

  XWPFDocument doc = new XWPFDocument(OPCPackage.open(file));

  // Replace paragraphs.

  FileOutputStream out = new FileOutputStream(filePath); 
  doc.write(out);
  out.close();
  doc.close();

  Files.deleteIfExists(Paths.get(tmpFilePath));
 }

}

Конечно, недостатком является использование дополнительного хранилища файлов, даже временного.

...