Java, как избежать перезаписи файла шаблона при поиске и замене в Apache POI

Я использую Apache POI 3.13 и пытался искать и заменять тексты из заданного файла шаблона, а затем сохранять новый сгенерированный .docx. Вот мой код:

public static void main(String[] args) throws InvalidFormatException, IOException {
    String filePath = "Sample.docx";
    File outputfile = new File("SampleProcessed.docx");

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

    for (XWPFParagraph p : doc.getParagraphs()) {
        List<XWPFRun> runs = p.getRuns();
        if (runs != null) {
            for (XWPFRun r : runs) {
                String text = r.getText(0);
                if (text != null && text.contains("$VAR")) {
                    text = text.replace("$VAR", "JohnDoe");
                    r.setText(text, 0);
                }
            }
        }
    }

    doc.write(new FileOutputStream(outputfile));
    doc.close();
    System.out.println("Done");
    Desktop.getDesktop().open(outputfile);
}

Это выглядит довольно просто, но когда я запускаю этот код, документ «Sample.docx» также заменяется. В итоге у меня есть два документа с одинаковым содержимым.

Это нормальное поведение POI? Я думал, что открытие документа только загружает его в память, а затем выполняет «doc.write(OutputStream);» сбросил бы на диск.

Я пытался писать в тот же «filePath», но, как и ожидалось, он выдает исключение, так как я пытаюсь записать в открытый в данный момент файл.

Единственное, что сработало, это когда я сначала скопировал файл шаблона и вместо этого использовал эту копию. Но теперь у меня есть 3 файла, первый из которых был исходным шаблоном «Sample.docx», а остальные 2 имеют одинаковое содержимое (SampleProcessed.docx и SampleProcessedOut.docx).

Это сработало, но это довольно расточительно. Есть ли способ сделать это? Я что-то делаю не так, возможно, я неправильно открываю документ Word?


person yev    schedule 14.02.2016    source источник


Ответы (1)


Поскольку вы используете

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

чтобы создать XWPFDocument, OPCPackage открывается из filePath в режиме READ_WRITE. Если это будет закрыто, оно также будет сохранено. См. https://poi.apache.org/apidocs/org/apache/poi/openxml4j/opc/OPCPackage.html#close%28%29.

OPCPackage будет закрыто, а XWPFDocument будет закрыто.

Но почему вы так делаете? Почему бы нет

XWPFDocument doc = new XWPFDocument(new FileInputStream(filePath));

?

При этом XWPFDocument будет создаваться в памяти только с новым OPCPackage без привязки к файлу.

person Axel Richter    schedule 14.02.2016
comment
Это сработало! Спасибо! Я пропустил это. Извините, я должен был прочитать документацию заранее. Я думал, что OPCPackage — единственный способ открыть файл .docx. Спасибо еще раз! - person yev; 14.02.2016
comment
Существует также версия open() с параметром PackageAccess, в котором вы можете указать READ как открытый режим и, таким образом, также избежать обратной записи данных, см. poi.apache.org /apidocs/org/apache/poi/openxml4j/opc/ - person centic; 15.02.2016
comment
@centic: Вы пробовали это? Как вы измените текст в пределах Runs, если OPCPackage открыт только для чтения? - person Axel Richter; 15.02.2016