System.IO.File.Delete () / System.IO.File.Move () иногда не работает

Программа Winforms должна сохранять некоторую информацию времени выполнения в файл XML. Размер файла иногда может составлять пару сотен килобайт. Во время бета-тестирования мы обнаружили, что некоторые пользователи без колебаний завершали процессы, казалось бы, случайным образом, что иногда приводило к тому, что файл был наполовину записан и, следовательно, поврежден.

Таким образом, мы изменили алгоритм, чтобы сохранить во временный файл, а затем удалить его. реальный файл и сделать ход.

В настоящее время наш код выглядит так ..

private void Save()
{
    XmlTextWriter streamWriter = null;
    try
    {
        streamWriter = new XmlTextWriter(xmlTempFilePath, System.Text.Encoding.UTF8);

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyCollection));

        xmlSerializer.Serialize(streamWriter, myCollection);

        if (streamWriter != null)
            streamWriter.Close();

        // Delete the original file
        System.IO.File.Delete(xmlFilePath);

        // Do a move over the top of the original file 
        System.IO.File.Move(xmlTempFilePath, xmlFilePath);
    }
    catch (System.Exception ex)
    {
        throw new InvalidOperationException("Could not save the xml file.", ex);
    }
    finally
    {
        if (streamWriter != null)
            streamWriter.Close();
    }
}

Это работает в лабораторных условиях и в производстве почти все время. Программа работает на 12 компьютерах, и этот код вызывается в среднем каждые 5 минут. Примерно один или два раза в день мы получаем это исключение:

System.InvalidOperationException: 
Could not save the xml file. 
---> System.IO.IOException: Cannot create a file when that file already exists.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.__Error.WinIOError()
at System.IO.File.Move(String sourceFileName, String destFileName)
at MyApp.MyNamespace.InternalSave()

Это как если бы удаление на самом деле не отправлялось на жесткий диск до того, как было выполнено перемещение.

Это происходит на машинах Win7.

Пара вопросов: есть ли какая-то концепция Flush () , которую можно сделать для всей дисковой операционной системы? Это ошибка моего кода, .net, ОС или чего-то еще? Следует ли мне добавить какой-нибудь Thread.Sleep (x) ? Может быть, мне сделать File.Copy (src, dest, true) ? Следует ли мне написать следующий код? (Но это выглядит довольно глупо.)

while (System.IO.File.Exists(xmlFilePath))
{
    System.IO.File.Delete(xmlFilePath);
}

// Do a move over the top of the main file 
bool done = false;
while (!done)
{
    try
    {
        System.IO.File.Move(xmlTempFilePath, xmlFilePath);
        done = true;
    }
    catch (System.IO.IOException)
    {
        // let it loop
    }
}

Кто-нибудь видел это раньше?

5
задан Brian Tompsett - 汤莱恩 7 August 2015 в 20:14
поделиться