在使用旧的INI文件多年后,我们最近开始使用XML文件。
我的同事发现了一些使用System.Xml.XmlDocument.Save的CodeProject示例代码。当两个程序试图同时写入同一个文件时,我们会遇到异常。
System.IO.IOException:进程 无法访问文件'C:\ Test.xml' 因为它被另一个人使用 过程
事后看来这很明显,但我们没有预料到它,因为通过Win32 API访问INI文件没有这个限制。我假设Win32调用完成了一些仲裁,它的工作级别高于XmlDocument.Save方法。
我希望.Net库中某处有更高级别的XML例程,它们与Win32函数类似,但不知道从哪里开始查找。
或者我们可以设置文件访问权限以允许多个程序写入同一个文件?
时间很短(就像几乎所有的SW项目一样),如果我们无法快速找到解决方案,我们就必须抓住我们的鼻子并回到INI文件。
答案 0 :(得分:5)
这不起作用。即使这两个进程可以写入同一个文件,它也只会损坏您的文件。如果你真的需要同时编写多个程序,我会改用数据库。
或者您可以将单个XML文件拆分为单独的文件吗?让每个进程写入自己的文件,然后在“读取”方法中将所有文件组合在一起。
答案 1 :(得分:2)
如果这些程序在同一个会话中运行,您可以创建一个单独的类来处理对文件的写入,并使用Singleton(或Multiton映射到多个文件名)设计模式来保证此类的一个实例。这将消除您的I / O异常。只需确保在每个“写入文件”请求中刷新此新类中的缓冲区。
注意:这将为您的程序引入全局状态。由于这个原因,单身人士被认为是一种反模式。
此外,这可能不适用于XML文件,因为它们形成树结构,这意味着在对其进行写入更改之前必须重新读取整个文件(您不能简单地“追加”到文件的末尾或者你会破坏它。)
我认为您需要检查您尝试使用XML的原因。如果您尝试使用它像“哑数据库”,您应该考虑转移到像SQLite这样的真正“精简”数据库。如果你只需要重复追加到文件的末尾,那么使用像.ini这样的平面文件没有任何问题。
答案 2 :(得分:1)
据我所知,很难让多个进程写到文件 - 如何处理并发?
但是,如果你想要一个文件读取,而另一个文件写入,那将是有效的(只要你不介意读者可能读取稍微旧的文件)。如果是这样,请使用通过只读文件访问初始化的FileStream中传递的XmlDocument.Load
函数。
System.Xml命名空间的许多(大多数?)也会有线程安全重载 - 但听起来你想要跨进程文件访问,这样除非你可以将你的所有应用程序实例都折叠成一个过程
因此,如果我是你,我会考虑一个支持多进程访问的更丰富的数据存储。某种数据库是最明显的答案。
编辑:根据评论进行了更正。
答案 3 :(得分:1)
拆分文件的另一种方法是使用数据库 - 那里有XML数据库,Wikipedia列出了其中一些数据库。
我不能保证他们中的任何一个。
答案 4 :(得分:1)
嗯,您可以通过确保在编写文件时关闭文件来解决第一个问题,然后重试打开它。然后,您需要将其保持打开状态,读取它,合并任何更改,然后再将其写出来。 (您必须合并更改,否则您将覆盖应用程序读取文件和再次写入之间所做的更改)。
INI文件已被取代两次 - 一次由注册表取代,然后由ConfigurationManager取代您可能想要试验ConfigurationManager。如果文件已更改或无法写入,Configuration.Save似乎会抛出异常 - 在这种情况下捕获异常并重试几次。
答案 5 :(得分:0)
XML文件对其结构(架构/ DTD等)比对INI文件更敏感。此外,Win32中的INI方法隐藏了您的文件访问的复杂性。从理论上讲,你可以想出某种线程安全的编写器,它锁定在标签级别而不是文件级别,但它不是一个开箱即用的功能。