当前位置: 首页 > 知识库问答 >
问题:

试图理解如何从ApachePOI保存对Word文档的更改

祖波光
2023-03-14

我有一个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行,则不会对当前文档进行任何更改(当然,也不会创建复制文档)。

如果我保留所有4行未注释,则会创建带有更改的复制文档,并且更改也会写入源文档。

如果我注释掉第四行,我会得到一个有更改的目标文档,而源文档保持不变。

最后一个是我想要的,我可以写我的代码来做到这一点。但是我希望在文档被更改后关闭它会改变它或不改变它,并且改变它不取决于我是否将更改写入了另一个文件。

有人能解释一下吗?

共有1个答案

毛德曜
2023-03-14

罪魁祸首是:XWPFDocument doc=newxwpfdocument(OPCPackage.open(source)) 。特别是:OPCPackage。开源

当静态OPCPackage打开(java.lang.String path)时,OPCPackage从具有读/写权限的文件路径path的底层文件打开。另外,它保持与基础文件的直接连接。这节省了一些内存,但也有缺点,正如您现在将看到的。

XWPFDocument中的所有更改都在该OPCPackage中进行,但首先在运行内存中进行。

在调用doc时。编写,它调用POIXMLDocument。write(java.io.OutputStream stream),首先底层的OPCPackage会得到更新。然后,更改后的OPCPackage通过给定的OutputStream流保存到目标文档中。所以不用调用doc。写入文件中没有任何内容会被更改,但只会保留在随机访问内存中。

然后,当doc.close()被调用时,OPCPackage.close被调用。这将关闭打开的可写包并保存其内容。由于OPCPackage直接连接到基础文件,它将内容保存到该文件中。这就是为什么更改也被写入源文档的原因。

这应该可以解释你的观察结果。

XWPF文档还提供了构造函数XWPF文档(java.io.InputStream)。这在内部调用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();
...

 类似资料:
  • 目前,我从文档中获得的所有文本如下所示:

  • 我正在尝试创建一个包含多列的word文档。这样做(而不是使用表)的原因是,数据将跨越多个页面,在添加到新页面之前,我只能用列填充整个页面。 可以用ApachePOI实现吗?谢谢

  • 我需要一个表格,第一行和第二行的单元格合并在一起。 大概是这样的: 桌子的图片(我不能张贴图片)http://i.stack.imgur.com/dAO6j.png 我一直在复习与本主题相关的所有问题,并找到了一些将网格跨度应用于单元的答案,但我找不到真正的解决方案。 以下是我从谷歌和本网站获得的示例代码: 我从这段代码中得到的信息如下: 我试图用

  • 问题内容: 在同一页面中提到的oodocx模块会将用户引向一个似乎不存在的/ examples文件夹。 我已经阅读了python-docx 0.7.2的文档,以及在上可以找到的所有内容,因此请相信我已经完成了“作业”。 Python是我所知道的唯一语言(初学者+,也许是中级),所以请不要假定对C,Unix,xml等有任何了解。 任务:打开其中包含一行文本的ms-word 2007+文档(为简单起见

  • 我已经为Word创建了一个插件。我正在尝试通过单击按钮更新word文档中的自定义属性的值。但却得不到拯救。我写的代码是: 但如果我在文档中添加一个空格然后保存它。然后保存自定义属性的值。代码为: 为什么行为是这样的。我不想在我的文档中添加任何额外的空白处。请帮帮我。提前道谢。

  • 我想用vba来保护我的word文档。 的确,这是可能的,但我已经通过以下链接搜索了如何取消文档保护: http://www.aurelp.com/2015/04/01/how-to-unlock-a-microsoft-word-document-step-by-stepsolved/ 有没有其他方法可以成功地保护文档不被未经授权的用户使用?