Java Apache POI: проблема с чтением/записью из файла .doc

Я пишу код для чтения файла .doc в качестве шаблона и записи данных в новый файл .doc после различных итераций. Кажется, в моем коде есть простая проблема, которую я не могу понять.

Ниже приведен код, который я написал: [Я получил базовый скелет только в stackoverflow.]

public class HWPFTest {

  public static void main(String[] args) {
        String inputFile = "F:\\docx\\input.doc";
        String outputFile = "F:\\docx\\output.doc";
        POIFSFileSystem fs = null;

        try {
              for (int i = 0; i < 3; i++) {
                    fs = new POIFSFileSystem(new FileInputStream(inputFile));
                    HWPFDocument doc = new HWPFDocument(fs);
                    System.out.println("LOOOOOOOOOOOOP ----> " + i);
                    doc = replaceText(doc, "$count", String.valueOf(i));
                    doc = replaceText(doc, "$filename", "FileName" + i);
                    doc = replaceText(doc, "$inputFile", "Input" + i);
                    doc = replaceText(doc, "$outputFile", "Output" + i);
                    doc = replaceText(doc, "$message", "Message" + i);
                    doc = replaceText(doc, "$snap", "Snapshot" + i);
                    saveWord(outputFile, doc);
              }
              System.out.println("DONE...");
        }
        catch (FileNotFoundException e) {
              e.printStackTrace();
        } catch (IOException e) {
              e.printStackTrace();
        }
  }

  private static HWPFDocument replaceText(HWPFDocument doc, String findText, String replaceText) {
        Range r1 = doc.getRange();
        for (int i = 0; i < r1.numSections(); ++i) {
              Section s = r1.getSection(i);
              for (int x = 0; x < s.numParagraphs(); x++) {
                    Paragraph p = s.getParagraph(x);
                    for (int z = 0; z < p.numCharacterRuns(); z++) {
                          CharacterRun run = p.getCharacterRun(z);
                          String text = run.text();
                          if (text.contains(findText)) {
                               run.replaceText(findText, replaceText);
                               System.out.println("findText: " + findText + " replaceText: " + replaceText);
                          }
                    }
              }
        }
        return doc;
  }


  private static void saveWord(String filePath, HWPFDocument doc) throws FileNotFoundException, IOException {
        FileOutputStream out = null;
        try {
              // Add true to make the data append possible in output stream.
              out = new FileOutputStream(filePath, true);
              doc.write(out);
              out.flush();
        } catch (Exception ex) {
              ex.printStackTrace();
        } finally {
              out.close();
        }
  }

}

Код работает без проблем. Вот как выглядит input.doc: input.doc

После успешного запуска также создается файл output.doc. Но проблема в том, что он содержит данные только для первого цикла.

В идеале он должен содержать данные для всех 3-х итераций, но он содержит данные только для первой, а потом ничего нет. Он также не показывает никаких ошибок/исключений во время выполнения. Я также убедился, что для выходного потока опция добавления будет иметь значение true.

Вот как выглядит файл output.doc: output.doc

Не уверен, что я делаю неправильно.

Когда я запускаю программу, я вижу в выводе ниже,

LOOOOOOOOOOOOP ----> 0 findText: $count replaceText: 0 findText: $filename replaceText: FileName0 findText: $inputFile replaceText: Input0 findText: $outputFile replaceText: Output0 findText: $message replaceText: Message0 findText: $snap replaceText: Snapshot0 LOOOOOOOOOOOOP ----> 1 findText: $count replaceText: 1 findText: $filename replaceText: FileName1 findText: $inputFile replaceText: Input1 findText: $outputFile replaceText: Output1 findText: $message replaceText: Message1 findText: $snap replaceText: Snapshot1 LOOOOOOOOOOOOP ----> 2 findText: $count replaceText: 2 findText: $filename replaceText: FileName2 findText: $inputFile replaceText: Input2 findText: $outputFile replaceText: Output2 findText: $message replaceText: Message2 findText: $snap replaceText: Snapshot2 DONE...

Поскольку я инициирую входной файл как новый на каждой итерации. Поэтому я нахожу все элементы $ во время итерации. Просто они не добавляются в окончательный файл.

Может кто-нибудь помочь здесь? Большое спасибо.


person WebNoob    schedule 11.11.2016    source источник


Ответы (2)


Вы открываете файл шаблона, меняете содержимое и сохраняете его в "F:\docx\output.doc". Вы делаете это 3 раза и каждый раз перезаписываете выходной файл.

Будет гораздо лучше подготовить строку в цикле, а затем только один раз заменить в документе. Ваш метод main будет выглядеть так:

public static void main(String[] args) {
        String inputFile = "F:\\docx\\input.doc";
        String outputFile = "F:\\docx\\output.doc";
        POIFSFileSystem fs = null;

        String counts = "";

        try {
            for (int i = 0; i < 3; i++) {
                counts += String.valueOf(i) + "; ";
            }
            fs = new POIFSFileSystem(new FileInputStream(inputFile));
            HWPFDocument doc = new HWPFDocument(fs);
            doc = replaceText(doc, "$count", counts);
            saveWord(outputFile, doc);
        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
person D. Krauchanka    schedule 11.11.2016
comment
Я добавил вывод консоли, о котором идет речь выше, который я вижу, когда запускаю программу. Также указано, что элементы $ находятся и заменяются при каждой итерации. - person WebNoob; 11.11.2016
comment
Да, я немного ошибся) вы открываете файл шаблона, меняете содержимое и сохраняете в F:\\docx\\output.doc. Вы делаете это 3 раза и каждый раз перезаписываете выходной файл. Итак, попробуйте решение, которое я предоставил вам в ответ. - person D. Krauchanka; 11.11.2016
comment
На самом деле содержимое, которое я показываю, является фиктивным содержимым, для простоты, чтобы его могли прочитать все. Фактическим содержимым будут имена файлов с путем, которые также будут содержать специальные символы в имени файла или пути к файлу. Поэтому, если я попытаюсь добавить это в строку, она сломается из-за этого. То, что у меня сейчас есть, работает отлично. Единственная проблема в том, что я не знаю ни одного метода в POI, который помог бы мне добавить содержимое всех итераций в один файл. Знаете ли вы о какой-либо другой технике, которая может сработать. - person WebNoob; 11.11.2016

Очевидно и удивительно, что Apache POI не имеет никакого метода записи с добавлением к существующему текстовому документу. Таким образом, вышеуказанный подход не работает.

Я также пробовал Apache FileUtils, но он не сохраняет форматирование документа Word. Я также пробовал docx4j, но он работает только с файлами docx, а его служебный класс слияния платный.

Существует еще один фреймворк, Aspose Words, который обеспечивает гораздо лучший контроль и гибкость. Он позволяет добавлять содержимое к существующему документу с ограничением в 1150 символов. Но это слишком много для моего требования, чтобы беспокоиться, поскольку мое письмо не превышало установленный лимит.

Так что я использовал это, чтобы достичь того, что я хотел сделать. Наконец-то это успех.

Спасибо за помощь @D. Краучанка

person WebNoob    schedule 22.11.2016