将修改后的WordprocessingDocument保存为新文件

51

我正在尝试打开一个Word文档,修改一些文本,然后将更改保存到一个新文档中。我可以使用以下代码完成第一步,但我无法想出如何将更改保存到一个新文档(指定路径和文件名)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using DocumentFormat.OpenXml.Packaging;
using System.IO;

namespace WordTest
{
class Program
{
    static void Main(string[] args)
    {
        string template = @"c:\data\hello.docx";
        string documentText;

        using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(template, true))
        {
            using (StreamReader reader = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
            {
                documentText = reader.ReadToEnd();
            }


            documentText = documentText.Replace("##Name##", "Paul");
            documentText = documentText.Replace("##Make##", "Samsung");

            using (StreamWriter writer = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
            {
                writer.Write(documentText);
            }
        }
      }
    }
}

我完全是一个新手,所以请原谅这个基础问题!


那些通过谷歌搜索到此并发现我们基本上只是按照以下步骤进行操作:https://learn.microsoft.com/en-us/office/open-xml/how-to-search-and-replace-text-in-a-document-part,但是我们正在尝试将其保存在一个新文档中,而不是原始文档。 - vapcguy
5个回答

52
如果您使用MemoryStream,您可以像这样将更改保存到新文件中:
byte[] byteArray = File.ReadAllBytes("c:\\data\\hello.docx");
using (MemoryStream stream = new MemoryStream())
{
    stream.Write(byteArray, 0, (int)byteArray.Length);
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))
    {
       // Do work here
    }
    // Save the file with the new name
    File.WriteAllBytes("C:\\data\\newFileName.docx", stream.ToArray()); 
}

2
很好地适应了 https://learn.microsoft.com/en-us/previous-versions/office/office-12//ee945362(v=office.12) 的内容。如果不想使用 File.WriteAllBytes( ... ),也可以使用 using (FileStream fileStream = new FileStream("C:\\data\\newFileName.docx", System.IO.FileMode.CreateNew)) { stream.WriteTo(fileStream); }。如果只想获取字节,则可以在 "wordDoc" using 块关闭之后,在中间执行 byteArray = stream.ToArray(); - vapcguy
如果这个解决方案对你不起作用,只需在“// 在此处执行工作”行的末尾写入以下行:wordDoc.Close(); >> 这个命令实际上是将所有内容写入流中的。 - Luis Gouveia

18

在Open XML SDK 2.5中:

    File.Copy(originalFilePath, modifiedFilePath);

    using (var wordprocessingDocument = WordprocessingDocument.Open(modifiedFilePath, isEditable: true))
    {
        // Do changes here...
    }

wordprocessingDocument.AutoSave 默认为 true,因此 Close 和 Dispose 会保存更改。由于使用块会调用 wordprocessingDocument.Close,因此不需要显式调用。

这种方法不需要像已接受的答案那样将整个文件内容加载到内存中。对于小文件来说,这不是问题,但在我的情况下,我必须同时处理更多带有嵌入式 xlsx 和 pdf 内容的 docx 文件,因此内存使用量会相当高。


5

只需将源文件复制到目标位置并在那里进行更改。

File.copy(source,destination);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(destination, true))
    {
       \\Make changes to the document and save it.
       wordDoc.MainDocumentPart.Document.Save();
       wordDoc.Close();
    }

希望这个能够奏效。

2
  1. 看起来你想写的是 wordDoc.Save()
  2. 没有 Save() 方法。所以这对我来说似乎不是一个有效的解决方案。
我有什么遗漏吗?
- Daniel Gray
请注意,此代码 MainDocumentPart.Document.Save() 不会保存整个包/Word文档。还有其他需要保存的部分(我的问题是脚注没有保存,这些不在 MainDocumentPart 下)。最终我使用了被接受的答案,而不是试图弄清楚哪些部分需要调用保存。 - George Duckett
对于那些你已经单独保存的人。 - Mohamed Alikhan
在Open XML SDK 2.5中,不必显式调用Save,如果WordprocessingDocument.AutoSave为true,则Close和Dispose将保存。也不必显式调用Close,因为using块将调用Dispose,进而调用Close。 - user3285954

3
这种方法允许你在不将整个“模板”文件批处理成byte[]的情况下缓存它,这可能使其资源消耗更少。
var templatePath = @"c:\data\hello.docx";
var documentPath = @"c:\data\newFilename.docx";

using (var template = File.OpenRead(templatePath))
using (var documentStream = File.Open(documentPath, FileMode.OpenOrCreate))
{
    template.CopyTo(documentStream);

    using (var document = WordprocessingDocument.Open(documentStream, true))
    {
        //do your work here

        document.MainDocumentPart.Document.Save();
    }
}

-2

对我来说,this 可以很好地工作:

// To search and replace content in a document part.
public static void SearchAndReplace(string document)
{
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
    {
        string docText = null;
        using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
        {
            docText = sr.ReadToEnd();
        }

        Regex regexText = new Regex("Hello world!");
        docText = regexText.Replace(docText, "Hi Everyone!");

        using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
        {
            sw.Write(docText);
        }
    }
}

2
这将其保存到同一文档中,因此并没有回答问题。 - Alan Macdonald

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接