1

我们有一个充当表单设计器的网站应用程序。

表单数据存储在 XML 文件中。每个表单都有自己的 xml 文件。

当我编辑表单时,我基本上是重新创建 XML 文件。

public void Save(Guid form_Id, IEnumerable<FormData> formData)
{
    XDocument doc = new XDocument();
    XElement formsDataElement = new XElement("FormsData");
    doc.Add(formsDataElement);
    foreach (FormData data in formData)
    {
        formsDataElement.Add(new XElement("FormData",
                                 new XAttribute("Id", data.Id)
                                 new XAttribute("Name", data.Name)
                                 // other attributes
                             ));
    }

    doc.Save(formXMLFilePath);
}

这很好用,但我想确保两个用户不会同时更新 XML 文件。我想以某种方式锁定它。

如何单独锁定每个文件的保存过程?

我可以像下面那样锁定保存功能,但这会锁定所有用户,即使他们保存了不同的 XML 文件。

private static readonly object _lock = new object();
public void Save(Guid form_Id, IEnumerable<FormData> formData)
{
    lock(_lock)
    {
        XDocument doc = new XDocument();
        foreach (FormData data in formData)
        {
            // Code
        }

        doc.Save(formXMLFilePath);
    }
}
4

3 回答 3

2

为了防止同时写入文件,该方法在内部使用以下构造函数XDocument.Save创建一个:FileStream

new FileStream(
    outputFileName,
    FileMode.Create,
    FileAccess.Write,
    FileShare.Read,
    0x1000,
    UseAsync)

该选项FileShare.Read可防止同时发生多个写入。如果您尝试同时执行两次写入,您最终会IOException被抛出。

您可能需要编写一些代码来处理这种可能性。这个答案https://stackoverflow.com/a/50800/138578应该准确地提供如何处理被锁定的文件并重试直到文件可用。

如果您的文档又小又多,那么您不应该经常遇到这种情况,如果有的话。

于 2013-01-14T10:45:43.547 回答
1

尝试这样的事情:

FileStream file = new FileStream(formXMLFilePath,FileMode.Create,FileAccress.Write,FileShare.None);

try {
    doc.Save(file);
} finally {
    file.Close();
}

这使用了 aFileStream并且我们提供了一个FileShare模式。在我们的例子中,我们专门锁定文件,以便只有我们可以写入它。

但是,这仅仅意味着后续写入将失败,因为存在锁定。

为了解决这个问题,我倾向于有一个队列和一个单独的线程,唯一的工作是处理队列并写入文件系统。

然而,另一种解决方案是简单地尝试访问该文件,如果失败,请稍等片刻,然后再试一次。这将让你做一些类似于lock它等待直到它可以访问然后继续的事情:

private static bool IsLocked(string fileName)
{
    if (!File.Exists(fileName)) return false;

    try {
        FileStream file = new FileStream(fileName,FileMode.Open,FileAccess.Write,FileShare.None);

        try {
            return false;
        } finally {
            file.Close();
        }
    } catch (IOException) {
        return true;
    }
}

public void Save(Guid form_Id, IEnumerable<FormData> formData)
{
    while (IsLocked(formXMLFilePath)) Thread.Sleep(100);

    FileStream file = new FileStream(formXMLFilePath,FileMode.Create,FileAccress.Write,FileShare.None);

    try {
        doc.Save(file);
    } finally {
        file.Close();
    }
}
于 2013-01-14T10:36:44.470 回答
0

打开 xml 文件后,您没有关闭 xml 文件连接。所以我认为你需要在你的函数结束时首先关闭你的连接。

你可以用这个

filename.Close();

我希望这能帮到您

于 2013-01-14T10:37:03.787 回答