我打算使用XDocument.Load()加载xml文件,更新某些元素的值,然后使用XDocument.Save()保存它。阅读效果很好,保存只是行不通。
我的代码:
class XmlDocHandler
{
private string filePath;
private XDocument xmlDoc;
private IList<XElement> updatedElements;
public IEnumerable<XElement> Elements => xmlDoc.Descendants();
public IEnumerable<XElement> UpdatedElements => updatedElements;
public XmlDocHandler(string filePath)
{
this.filePath = filePath;
ReloadFromFile();
updatedElements = new List<XElement>();
}
public void UpdateElements(IEnumerable<XElement> newElements)
{
updatedElements = new List<XElement>();
foreach (XElement newElement in newElements)
{
XElement element = xmlDoc.Descendants()
.FirstOrDefault(x => x.Name.LocalName == newElement.Name.LocalName);
if (element != null)
{
if (element.Value != newElement.Value)
{
element.Value = newElement.Value;
updatedElements.Add(element);
}
}
}
}
public void ReloadFromFile()
{
bool success = false;
if (File.Exists(filePath))
{
try
{
xmlDoc = XDocument.Load(filePath);
success = true;
}
catch
{
}
}
if (!success)
{
xmlDoc = new XDocument();
}
}
public void WriteToFile()
{
xmlDoc.Save(filePath);
}
}
据我所知,它的一系列操作序列,没有并行或其他奇特的东西,可能会阻塞我的文件。我没有发现XDocument.Load(“ c:\ file.xml”)会在文件上创建锁定的迹象。
我试图替换直接操作
xmlDoc = XDocument.Load(filePath);
和
xmlDoc.Save(filePath);
基于流的方法在这里找到: XDocument.Save() unable to access file 和这里 c# xml.Load() locking file on disk causing errors 这样它们看起来像这样:
正在加载..
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
xmlDoc = XDocument.Load(fs);
}
或
using (var sr = new StreamReader(filePath))
{
xmlDoc = XDocument.Load(sr);
}
和写作..
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Write, FileShare.Write))
{
xmlDoc.Save(fs);
}
无论我做什么,正确关闭流并确保未在任何编辑器中打开文件或以其他方式使用该文件,愚蠢的文件始终“被另一个进程使用”。
我在这里没看到什么?有问题的文件位于.exe文件旁边的我的VS2017 Pro的Debug输出文件夹中。我不知道该文件夹中的写访问权限有限。
答案 0 :(得分:2)
我发现了导致此惨败的错误!
此问题的原因与XDocument.Load()
或.Save()
没有关系。尽管为解决问题感到欣慰,但我也很尴尬地承认我几年前做出的一种自己的实现方式导致了这种情况。
我曾经为System.Windows.Forms.OpenFileDialog()
创建了一个包装器类,这将简化我经常使用的OFD类的配置。在其中,我使用了类似的
var ofd = new OpenFileDialog();
try
{
if((var stream = ofd.OpenFile()) != null)
{
return ofd.FileName;
}
else
{
return "file already opened";
}
}
catch
{
return "error";
}
,同时将ofd
和stream
引用保留为实例变量。现在看这段代码会让我颤抖(或发笑),但那时候我再也没有更好的了。当然,这现在已经让我很痛苦了,因为我没有关闭那条小溪!我几年前犯下的罪行现在使我花了将近2天的时间。
我的补救措施:我重写了OFD包装器类以使用Microsoft.Win32.OpenFileDialog
类,因为似乎没有任何基于流的东西会无意中锁定文件。
IDisposable.Dispose()
方法,阅读使用处置模式的using块语句。最后,使用VS中的整齐的概要分析功能,这些功能在我进行OFD包装时是不可用的,它们有助于发现此类问题。
感谢所有提供帮助的人和SO,以便向他们提供帮助。
答案 1 :(得分:0)
尝试
fs.Close();
也许
a
写完之后。 AFAIK IO流中正在进行某种缓存。可能有帮助。
致谢。