在程序生成的xml文件上共享冲突

时间:2014-12-29 02:05:23

标签: c# xml

我正在使用monodevelop编写C#控制台应用程序,最近我决定使用xml文件作为存储用户首选项的方法。创建,编写初始数据和阅读文件很容易完成,而且从我看到的更新它应该也是如此。但是,下面的代码会在路径上生成共享冲突:

public void Update (string username, PreferenceAttribute preferencename, string newvalue)
    {
        try 
        {
            ...
            //this is where it throws exception \/
            using (FileStream fs = new FileStream (filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                string attribute = preferencename.ToString ();
                doc = new XmlDocument ();
                doc.Load (fs);
                fs.Close ();
                XmlNode user = doc.SelectSingleNode ("//Users/User[@Name = '" + username + "']");
                XmlNode pref = user.SelectSingleNode("Pref");
                pref.Attributes[attribute].Value = newvalue;
                doc.Save (fs);
            }
        } catch (Exception ex)
        {
            //error details output
        }
    }

退出using块会导致错误发生在doc.save(fs)行,并导致文件丢失它所拥有的任何数据。我查看了其他帖子,但唯一的解决方案似乎是使用块。我需要一种方法来锁定文件(除非我的代码产生问题)。有什么帮助吗?

编辑:这是我尝试编辑的xml文档:

<?xml version="1.0" encoding="utf-8"?>
<!--Do not modify this auto-generated file. Doing so will cause unwanted behavior. If modification causes problems, delete this file and rerun the program-->
<Users>
  <User Name="Ben" Password="hello54">
    <Pref Gender="Male" Admin="false" Butler="Alfred" Eastereggs="false" />
  </User>
  <User Name="Admin" Password="admin">
    <Pref Gender="Male" Admin="true" Butler="Butler" Eastereggs="false" />
  </User>
</Users>

我认识到以这种方式存储密码和东西是不安全的;但是,我是一个尝试学习xml并培养我的C#技能的业余爱好者,所以暂时还可以。

堆栈跟踪:

Sharing violation on path /Users/Knoble/MonoProjects/Test_Console/Test_Console/bin/Debug/Preferences.xml
mscorlib
  at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) [0x0032f] in /private/tmp/source-mono-mac-3.10.0-branch/bockbuild-mono-3.10.0-branch/profiles/mono-mac-xamarin/build-root/mono-3.10.0/mcs/class/corlib/System.IO/FileStream.cs:320 
  at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share) [0x00000] in /private/tmp/source-mono-mac-3.10.0-branch/bockbuild-mono-3.10.0-branch/profiles/mono-mac-xamarin/build-root/mono-3.10.0/mcs/class/corlib/System.IO/FileStream.cs:132 
  at (wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
  at XMLPref.XMLPreferences.Update (System.String username, PreferenceAttribute preferencename, System.String newvalue) [0x0003d] in /Users/Knoble/MonoProjects/Test_Console/XMLPreferences/XMLPreferences.cs:299 
Void .ctor(String, FileMode, FileAccess, FileShare, Int32, Boolean, FileOptions)

1 个答案:

答案 0 :(得分:2)

您的代码存在两个问题。

如果您要求对文件(FileAccess.ReadWrite)进行写访问,则不能允许其他流/线程/程序同时读取(FileShare.Read)。

问题是,一旦Close Stream(例如FileStream,您就不能再读/写了)。您向操作系统发出信号,表明该文件现在可以被其他程序使用。

该问题的一个潜在解决方案是使用该文件两次:

using (FileStream fs = new FileStream (filepath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
    string attribute = preferencename.ToString ();
    doc = new XmlDocument ();
    doc.Load (fs);
}
XmlNode user = doc.SelectSingleNode ("//Users/User[@Name = '" + username + "']");
XmlNode pref = user.SelectSingleNode("Pref");
pref.Attributes[attribute].Value = newvalue;
using (FileStream fs = new FileStream (filepath, FileMode.Open, FileAccess.Write, FileShare.None)) {
    doc.Save (fs);
}

您可以通过以下方式替换第二部分:

doc.Save (filepath);