使用OpenXmlPowerTools修改Word内容后合并报错:文件包含损坏数据
解决OpenXmlPowerTools合并Word模板时的“文件包含损坏数据”错误
问题背景
原本使用OpenXmlPowerTools合并Word模板的代码运行正常:
var sources = new List<Source>(); foreach (var fileName in fileName_List) { using (FileStream stream = System.IO.File.Open(filename, FileMode.Open)) { var memoryStream= new MemoryStream(); stream.CopyTo(memoryStream); sources.Add(new Source(new WmlDocument("", memoryStream), true)); } } var mergedDoc = DocumentBuilder.BuildDocument(sources); mergedDoc.SaveAs(resultFile);
但为了在合并前修改每个文件的占位符,调整代码后,调用mergedDoc.SaveAs(resultFile)时抛出错误:File contains corrupted data
调整后的代码:
foreach (var filename in fileName_List) { using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filename, true)) using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream())) { var docText = sr.ReadToEnd(); docText = docText.Replace("PlaceHolder", "NewValue"); using (var memoryStream= GenerateStreamFromString(docText)) { sources.Add(new Source(new WmlDocument("", memoryStream), true)); } } } public static MemoryStream GenerateStreamFromString(string s) { var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(s); writer.Flush(); stream.Position = 0; return stream; }
尝试改用ASCII编码将文本转为字节数组,错误依旧:
var docText = sr.ReadToEnd(); docText = docText.Replace("PlaceHolder", "NewValue"); byte[] bytes = Encoding.ASCII.GetBytes(docText); sources.Add(new Source(new WmlDocument("", bytes), true));
问题原因
直接通过StreamReader读取MainDocumentPart的流并做文本替换,会破坏Word文档的OpenXML结构:
- Word的
MainDocumentPart是XML格式,直接读写文本可能破坏XML的编码声明、命名空间或结构完整性 - 使用
StreamWriter或ASCII编码写入时,会改变原文档的编码格式,导致生成的文档不符合OpenXML规范,最终被判定为损坏数据
正确解决方案
必须通过OpenXML API操作文档内容,而非直接读写文本流。修改占位符的正确代码如下:
var sources = new List<Source>(); foreach (var filename in fileName_List) { // 复制原文件到内存流,避免修改原文件 using (var originalStream = new MemoryStream()) { using (var fileStream = File.OpenRead(filename)) { fileStream.CopyTo(originalStream); } originalStream.Position = 0; // 打开内存中的Word文档进行修改 using (var wordDoc = WordprocessingDocument.Open(originalStream, true)) { var mainPart = wordDoc.MainDocumentPart; var body = mainPart.Document.Body; // 遍历所有文本节点替换占位符 foreach (var text in body.Descendants<Text>()) { if (text.Text.Contains("PlaceHolder")) { text.Text = text.Text.Replace("PlaceHolder", "NewValue"); } } // 保存修改并重置流位置 wordDoc.Save(); originalStream.Position = 0; // 将修改后的流转为WmlDocument加入合并列表 sources.Add(new Source(new WmlDocument("", originalStream), true)); } } } var mergedDoc = DocumentBuilder.BuildDocument(sources); mergedDoc.SaveAs(resultFile);
补充说明
- 若占位符位于段落、表格等复杂结构中,可根据实际场景调整遍历逻辑,比如定位特定的
Paragraph或Run节点 - 直接操作XML文本极易引入编码、格式错误,始终优先使用OpenXML SDK提供的API修改文档内容
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

