调用静态方法写入XML时遇文件占用IO异常的解决咨询
你遇到的问题本质上是文件独占锁定导致的——WriteShipment方法已经通过XmlWriter打开了目标文件,而WriteAddress和WriteDate又尝试重新打开同一个路径的文件,操作系统不允许同一个进程同时对文件进行写入操作,所以抛出了那个异常。
下面是几种可行的解决方案,按推荐程度排序:
解决方案1:传递已打开的XmlWriter实例(最推荐)
这个方案的核心是让所有XML写入操作共用同一个XmlWriter,避免重复打开文件。你需要修改Address.WriteAddress和Date.WriteDate的方法签名,让它们接收已经创建好的XmlWriter,而不是文件路径。
修改后的代码示例:
1. 更新WriteShipment方法中的调用
public static void WriteShipment(Shipment s, string path) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = "\t"; // 使用using语句自动释放资源,比手动Close更安全 using (XmlWriter w = XmlWriter.Create(path, settings)) { w.WriteStartDocument(); w.WriteStartElement("Shipment"); w.WriteStartElement("id"); w.WriteString(s.id); w.WriteEndElement(); // 传递已打开的XmlWriter给子方法,而不是路径 Address.WriteAddress(s.from, w); Address.WriteAddress(s.to, w); Date.WriteDate(s.receiveDate, w); Date.WriteDate(s.deliverDate, w); w.WriteStartElement("sum"); w.WriteValue(s.sum); w.WriteEndElement(); w.WriteStartElement("currency"); w.WriteString(s.currency); w.WriteEndElement(); w.WriteStartElement("paid"); w.WriteValue(s.paid); w.WriteEndElement(); w.WriteEndElement(); w.WriteEndDocument(); } // using结束时自动关闭XmlWriter }
2. 修改Address.WriteAddress方法
public static void WriteAddress(Address addr, XmlWriter writer) { // 可以额外添加一个参数区分是from还是to地址,比如: // public static void WriteAddress(Address addr, XmlWriter writer, string nodeName) writer.WriteStartElement("from"); writer.WriteStartElement("street"); writer.WriteString(addr.street); // 替换成你的Address类实际字段 writer.WriteEndElement(); writer.WriteStartElement("city"); writer.WriteString(addr.city); writer.WriteEndElement(); // 写入其他Address字段... writer.WriteEndElement(); }
3. 修改Date.WriteDate方法
public static void WriteDate(Date date, XmlWriter writer) { // 同样可以添加参数区分是接收日期还是配送日期 writer.WriteStartElement("receiveDate"); writer.WriteStartElement("year"); writer.WriteValue(date.year); // 替换成你的Date类实际字段 writer.WriteEndElement(); writer.WriteStartElement("month"); writer.WriteValue(date.month); writer.WriteEndElement(); // 写入其他Date字段... writer.WriteEndElement(); }
方案优势:
- 完全避免了文件锁定冲突,所有写入操作共享同一个文件流
- 保证生成的XML结构完整、格式正确,不会出现多个Writer写入导致的标签错乱
- 代码更高效,不需要额外的内存开销
解决方案2:先写入内存再统一保存(兼容旧方法的折中方案)
如果你不想修改WriteAddress和WriteDate的方法签名,可以先让这些方法生成XML片段并返回字符串,然后在WriteShipment中把所有片段整合后一次性写入文件。
修改后的代码示例:
1. 修改Address.WriteAddress为返回XML字符串
public static string WriteAddress(Address addr) { using (var stringWriter = new StringWriter()) using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = "\t" })) { xmlWriter.WriteStartElement("from"); // 写入Address字段... xmlWriter.WriteEndElement(); return stringWriter.ToString(); } }
2. 更新WriteShipment方法
public static void WriteShipment(Shipment s, string path) { using (var stringWriter = new StringWriter()) using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = "\t" })) { xmlWriter.WriteStartDocument(); xmlWriter.WriteStartElement("Shipment"); // 写入基础字段... xmlWriter.WriteStartElement("id"); xmlWriter.WriteString(s.id); xmlWriter.WriteEndElement(); // 获取子方法生成的XML片段并写入 xmlWriter.WriteRaw(Address.WriteAddress(s.from)); xmlWriter.WriteRaw(Address.WriteAddress(s.to)); xmlWriter.WriteRaw(Date.WriteDate(s.receiveDate)); xmlWriter.WriteRaw(Date.WriteDate(s.deliverDate)); // 写入剩余字段... xmlWriter.WriteStartElement("sum"); xmlWriter.WriteValue(s.sum); xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement(); xmlWriter.WriteEndDocument(); } // 最后一次性写入文件 File.WriteAllText(path, stringWriter.ToString()); }
方案注意点:
- 要确保子方法返回的XML片段是合法的,没有未转义的特殊字符
- 这种方法会占用更多内存,不适合处理超大的Shipment数据
不推荐的方案:使用文件共享权限
有些开发者会尝试通过设置FileShare.Write来允许多个流写入同一个文件,但强烈不推荐这种做法:
// 不推荐!仅作反面示例 using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write)) using (XmlWriter w = XmlWriter.Create(fs, settings)) { // 原WriteShipment代码 }
多个XmlWriter同时写入同一个文件会导致XML标签错乱,生成的文件完全不符合XML规范,无法被正常解析。
内容的提问来源于stack exchange,提问作者Blabla
相关产品推荐
相关产品推荐

