Надежное сохранение файлов (File.Replace) в загруженной среде

Я работаю над серверным программным обеспечением, которому периодически необходимо сохранять данные на диск. Мне нужно убедиться, что старый файл перезаписывается, и файл не может быть поврежден (например, только частично перезаписан) в случае непредвиденных обстоятельств.

Я принял следующий шаблон:

string tempFileName = Path.GetTempFileName();
// ...write out the data to temporary file...
MoveOrReplaceFile(tempFileName, fileName);

... где MoveOrReplaceFile:

public static void MoveOrReplaceFile( string source, string destination ) {
    if (source == null) throw new ArgumentNullException("source");
    if (destination == null) throw new ArgumentNullException("destination");
    if (File.Exists(destination)) {
        // File.Replace does not work across volumes
        if (Path.GetPathRoot(Path.GetFullPath(source)) == Path.GetPathRoot(Path.GetFullPath(destination))) {
            File.Replace(source, destination, null, true);
        } else {
            File.Copy(source, destination, true);
        }
    } else {
        File.Move(source, destination);
    }
}

Это работает хорошо, пока сервер имеет монопольный доступ к файлам. Однако File.Replace, похоже, очень чувствителен к внешнему доступу к файлам. Каждый раз, когда мое программное обеспечение запускается в системе с антивирусом или системой резервного копирования в реальном времени, случайный файл Начинают появляться ошибки .Replace:

System.IO.IOException: невозможно удалить файл, который нужно заменить.

Вот несколько возможных причин, которые я устранил:

  • Неизданные дескрипторы файлов : using () гарантирует, что все дескрипторы файлов будут освобождены как можно скорее.
  • Проблемы с потоками : lock () охраняет весь доступ к каждому файлу.
  • Различные дисковые тома : File.Replace () не работает при использовании нескольких дисковых томов. Мой метод уже проверяет это и возвращается к File.Copy ().

И вот несколько предложений, с которыми я столкнулся, и почему я бы предпочел их не использовать:

  • Служба теневого копирования тома : это работает только до тех пор, пока проблемное стороннее программное обеспечение (резервное копирование и антивирусные мониторы и т. д.) также используют VSS.Использование VSS требует большого количества P / Invoke и имеет проблемы, связанные с платформой.
  • Блокировка файлов : В C # для блокировки файла требуется, чтобы FileStream оставался открытым. Это не позволит стороннему программному обеспечению, но 1) я все равно не смогу заменить файл с помощью File.Replace и 2) Как я уже упоминал выше, я предпочитаю сначала записать во временный файл, чтобы избежать случайного коррупция.

Я был бы признателен за любой вклад, чтобы заставить File.Replace работать каждый раз или, в более общем плане, надежно сохранять / перезаписывать файлы на диск.

25
задан matvei 21 January 2014 в 22:36
поделиться