XDocument.Save () что-то блокирует файл - PullRequest
0 голосов
/ 24 октября 2018

Я намерен загрузить XML-файл с помощью XDocument.Load (), обновить значения некоторых элементов, а затем сохранить его с помощью 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 () не может получить доступ к файлу и здесь c # xml.Load () блокирует файл надиск вызывает ошибки , чтобы они выглядели так:

Загрузка ..

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);
}

Независимо от того, что я делаю, правильно закрывая потоки и следя за тем, чтобы файл не открывался в каком-либо редакторе или использовался иным образом, глупый файл всегда «используется другим процессом».

Что именноя не вижу здесь?Данный файл находится в моей выходной папке Debug VS2017 Pro рядом с файлом .exe.Я не знаю, что у меня ограничен доступ для записи в эту папку.

Ответы [ 2 ]

0 голосов
/ 25 октября 2018

Я обнаружил ошибку, вызвавшую это фиаско!

Причина этой проблемы не имеет ничего общего с 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, потому что у него, похоже, нет никакоговещи, основанные на потоках, которые могли бы непреднамеренно заблокировать файлы.

Извлеченные уроки (и то, что я настоятельно рекомендую другим): никогда не доверяйте себе при использовании потоков или других конструкций, которые можно оставить открытыми и вызвать утечки памяти.Прочитайте инструкцию using, которая использует шаблон dispose, вызвав метод IDisposable.Dispose(), который обычно заботится о такой работе по очистке.И, наконец, используйте функции аккуратного профилирования в VS, которые не были доступны в то время, когда я делал свою оболочку OFD, они помогают обнаруживать такие проблемы.

Спасибо всем, кто помог, и SO, чтобы сделать их помощь доступной.

0 голосов
/ 24 октября 2018

попробуйте

fs.Flush();

и, возможно,

fs.Close();

после записи.AFAIK, в IO Streams происходит какое-то кэширование.Это может помочь.

С уважением.

...