我有一个 Word 文档 (docx);我想对该文档进行更改并将结果另存为另一个文件,将原始文件留在原处。我有以下代码说明我当前的问题:
package sandbox.word.doccopy;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
public class CopyTest
{
public static void main(String[] args) throws Exception
{
String sourceFilename = "CopyTestSource.docx";
String destinationFilename = "CopyTestResult.docx";
CopyTest docCopy = new CopyTest();
docCopy.copyTesting(sourceFilename, destinationFilename);
System.out.println("done");
}
public void copyTesting(String source, String destination)
throws IOException, InvalidFormatException
{
XWPFDocument doc = new XWPFDocument(OPCPackage.open(source));
// for each paragraph that has runs,
// put an exclamation at the end of the first run.
for (XWPFParagraph par : doc.getParagraphs())
{
List<XWPFRun> runs = par.getRuns();
if (runs.size() > 0)
{ XWPFRun run = par.getRuns().get(0);
String text = run.getText(0);
text = text + "!";
run.setText(text, 0);
}
}
// FileOutputStream fos = new FileOutputStream(destination);
// doc.write(fos);
// fos.close();
doc.close();
}
}
我用三种方法运行它,更改类文件底部的注释行。如您所见,有 3 行使用目标文件名创建文件输出流、写入并关闭它,还有 1 行仅关闭当前文档。
如果我注释掉第 3 行并保留第 1 行,则不会向当前文档写入任何更改(当然,也不会创建副本文档)。
如果我保留所有 4 行未注释,则会创建包含更改的副本文档,并且更改也会写入源文档。
如果我注释掉第 4 行,我会得到一个有更改的目标文档,而源文档保持不变。
最后一个是我想要的,我可以编写我的代码来做到这一点。但我希望在更改后关闭文档会更改它或不更改它,并且更改它不取决于我是否已将更改写入另一个文件。
任何人都可以阐明这一点吗?
最佳答案
罪魁祸首是:XWPFDocument doc = new XWPFDocument(OPCPackage.open(source));
。特别是这个:OPCPackage.open(source)
。
同时 static OPCPackage open(java.lang.String path) OPCPackage
从具有读/写权限的文件路径 path
的基础文件中打开。另外,它直接连接到底层文件。这可以节省一些内存,但也有缺点,正如您现在将要看到的那样。
XWPFDocument
中的所有更改都在该 OPCPackage
中进行,但首先在随机存取存储器中进行。
在调用 doc.write
时,调用 POIXMLDocument.write(java.io.OutputStream stream) ,首先底层的 OPCPackage
得到更新。然后更改的 OPCPackage
通过给定的 OutputStream 流
保存在目标文档中。因此,如果不调用 doc.write
,文件中的任何内容都不会更改,只会保留在随机存取存储器中。
然后 doc.close()
也被调用 OPCPackage.close被调用。这将关闭打开的可写包并保存其内容。由于 OPCPackage
直接连接到底层文件,它将内容保存到该文件中。这就是将更改也写入源文档的原因。
这应该可以解释您的观察结果。
XWPFDocument
也提供构造函数
XWPFDocument(java.io.InputStream is) .这在内部调用 OPCPackage.open(java.io.InputStream in) .这将打开 InputStream
中的 OPCPackage
。 OPCPackage
仅在随机存取存储器中,并且独立于源文件。这会使用更多内存,因为整个 OPCPackage
需要在随机存取内存中,但 OPCPackage.close
不会导致源文件发生变化。
所以我会做的是:
...
XWPFDocument doc = new XWPFDocument(new FileInputStream(source));
...
FileOutputStream fos = new FileOutputStream(destination);
doc.write(fos);
fos.close();
doc.close();
...
关于java - 试图了解从 Apache poi 保存对 Word 文档的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71285213/