如何通过OpenXML删除Word文档自定义属性?文档仍无法打开
修复OpenXML处理损坏Word文档自定义属性后无法打开的问题
问题描述
我尝试用OpenXML删除一个已损坏Word文档的自定义属性,代码能正常编译,但处理后的文档无法打开,弹出错误:
Word found unreadable content in ''. Do you want to recover the contents of this document? if you trust the source of this document, click yes
用户编写的代码如下:
public static MemoryStream DeleteCustomPropertiers(Stream fileStream) { var msStream = new MemoryStream(); fileStream.CopyTo(msStream); using (var document = WordprocessingDocument.Open(msStream, true)) { var properties = new Dictionary<string, string>(); if (document != null) { var customProps = document.CustomFilePropertiesPart; if (customProps != null) { if (customProps.Properties != null) { var props = from n in customProps.Properties.Elements<CustomDocumentProperty>() where n.Name == "Props1" || n.Name == "Props2" select n; for (int i = props.Count() - 1; i >= 0; i--) { var prop = props.ToList()[i]; prop.Remove(); } customProps.Properties.Save(); } } } msStream.Position = 0; document.MainDocumentPart.Document.Save(); document.Dispose(); return msStream; } }
问题分析与修复方案
1. 移除多余的手动资源释放
using语句会自动释放WordprocessingDocument对象,手动调用document.Dispose()会导致资源提前释放,引发流操作异常,直接删除该语句即可。
2. 修正属性删除逻辑
原代码中LINQ查询每次枚举都会重新获取元素,循环中多次调用ToList()会导致重复查询,且可能触发集合变更异常。应先将需要删除的属性转为List再遍历删除:
var propsToRemove = customProps.Properties.Elements<CustomDocumentProperty>() .Where(n => n.Name == "Props1" || n.Name == "Props2") .ToList(); foreach (var prop in propsToRemove) { prop.Remove(); }
3. 调整流位置设置时机
将msStream.Position = 0移到using块外部,确保文档完全保存并释放资源后,再重置流的读取位置。
4. 启用损坏文档修复模式
原文档本身已损坏,直接用OpenXML操作可能加剧损坏,需启用SDK的修复模式:
var settings = new OpenSettings { RepairMode = RepairMode.Repair }; using (var document = WordprocessingDocument.Open(msStream, true, settings)) { // 后续操作 }
5. 简化文档保存逻辑
不需要单独调用MainDocumentPart.Document.Save(),WordprocessingDocument在using块结束时会自动保存所有变更,单独调用可能导致保存不完整。
修正后的完整代码
public static MemoryStream DeleteCustomProperties(Stream fileStream) { var msStream = new MemoryStream(); fileStream.CopyTo(msStream); // 启用修复模式处理损坏文档 var settings = new OpenSettings { RepairMode = RepairMode.Repair }; using (var document = WordprocessingDocument.Open(msStream, true, settings)) { if (document?.CustomFilePropertiesPart?.Properties != null) { // 先转为List避免枚举时集合变更异常 var propsToRemove = document.CustomFilePropertiesPart.Properties .Elements<CustomDocumentProperty>() .Where(n => n.Name == "Props1" || n.Name == "Props2") .ToList(); foreach (var prop in propsToRemove) { prop.Remove(); } // 保存属性部分的变更 document.CustomFilePropertiesPart.Properties.Save(); } } // 重置流位置,供后续读取使用 msStream.Position = 0; return msStream; }
内容的提问来源于stack exchange,提问作者user20377051
相关产品推荐
相关产品推荐

