Open XML SDK - 使用 MemoryStream 作为 docx 持有者从模板 (dotx) 创建 docx

Posted

技术标签:

【中文标题】Open XML SDK - 使用 MemoryStream 作为 docx 持有者从模板 (dotx) 创建 docx【英文标题】:Open XML SDK - Create docx from template (dotx) using MemoryStream as docx holder 【发布时间】:2017-06-24 01:59:07 【问题描述】:

我正在尝试使用 OpenXML 2.5 库从 word 模板 (.dotx) 创建一个 .docx 文件。更确切地说,我正在尝试关注 this ,但我想使用 MemoryStream 而不是文件的路径打开文档。

所以在上面的链接中,方法是这样的:将模板文件复制到磁盘上的新文件中。以WordProcessingDocument 的形式打开新文件,将其类型更改为 Document 并添加对模板的引用(我不确定为什么这是必要的......)

我需要的是。从数据库中获取我的模板作为字节数组。将数组复制到流中并以WordProcessingDocument 的形式打开它。然后做和上面一样的事情。 我不想使用磁盘上的临时文件等等。我不明白的是为什么我要在新文档中引用模板文件(实际上,检查 docx 存档中的 xml 文件,它只是添加了一个包含模板名称的 xml 节点......为什么?)

现在,我的问题是,如果我使用 MemoryStream 而不是文件的物理路径,则生成的 docx 已损坏。我收到“Microsoft office 无法打开此文件,因为某些部分丢失或无效”。 如果我使用临时磁盘文件,它可以工作。 为什么会这样?

简化,我的代码如下所示:

byte[] result = null;
byte[] templateBytes = System.IO.File.ReadAllBytes("template.dotx");
using (MemoryStream templateStream = new MemoryStream())

    templateStream.Write(templateBytes, 0, (int)templateBytes.Length);

    using (WordprocessingDocument doc = WordprocessingDocument.Open(templateStream, true))
    
        doc.ChangeDocumentType(WordprocessingDocumentType.Document);
        var mainPart = doc.MainDocumentPart;

        //Here I should create an AttachedTemplate object and assign a relationship id to it, which also implies
        //setting a "reference" to the template ? I'm not using files so there's nothing to "reference" anyway
        // If it's doing more than just putting a visual reference to the template file, then why limit the way of referencing the template
        // only by using the Uri to the file? Please take a look at the above link to see what I'm referring to.

        //Write some text in the file ....
        mainPart.Document.Save();

        File.WriteAllBytes("Result.docx", templateStream.ToArray());
    

这给我一个损坏的 docx 文件。如果我从 MemoryStream 切换到从磁盘打开新的 docx 文件(使用 WordProcessingDocument 类的另一个构造函数),它可以工作。 我没有做错什么(比如在处理内存流后尝试将结果写入文件),所以它应该给我相同的结果。

我的代码有什么问题?

谢谢

【问题讨论】:

我知道这已经过时了,但您知道为什么需要附加模板文件吗?如果我跳过这一步怎么办? @Garima 没必要。我需要它是因为我有一个基本模板,其中包含结果文档所需的一些自定义创建的样式。但您也可以直接打开 .docx 文件。代码应该是一样的。 谢谢!即使我有一个带有自定义样式的基本模板(.dotx)。 【参考方案1】:

如果您将代码 File.WriteAllBytes 的最后一行从内部 using 块中取出,它应该可以正常工作。只需将该行放在外部 using 块的右大括号之前即可。

【讨论】:

感谢您的回答,迈克尔。太晚了,我没看到。你是对的,通过退出文档的 using 块,Open XML 正在保存更改并关闭/处置非托管资源。所以我基本上是尝试打开没有完全保存的东西。

以上是关于Open XML SDK - 使用 MemoryStream 作为 docx 持有者从模板 (dotx) 创建 docx的主要内容,如果未能解决你的问题,请参考以下文章

在 c# 中使用 Open Xml SDK 将 DataTable 导出到 Excel

Open XML SDK 2.0 - 如何更新电子表格中的单元格?

Open XML SDK - 使用 MemoryStream 作为 docx 持有者从模板 (dotx) 创建 docx

如何从 Word 文档中复制富文本内容控件的内容并使用 Open XML SDK 删除控件本身

开始学 Open XML SDK 2.5 for Microsoft Office

Open XML SDK 2.0 2.0.3920.0 和 2.0.5022.0 之间的重大更改