Я работаю над серверным программным обеспечением, которое периодически должно сохранять данные на диск. Мне нужно убедиться, что старый файл перезаписан и что файл не может быть поврежден (например, только частично перезаписан) в случае непредвиденных обстоятельств.
Я принял следующий шаблон:
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, похоже, очень чувствителен к внешнему доступу к файлам. Каждый раз, когда мое программное обеспечение работает в системе с антивирусом или системой резервного копирования в реальном времени, появляются случайные ошибки File.Replace:
System.IO.IOException: Невозможно удалить файл, подлежащий замене.
Вот несколько возможных причин, которые я устранил:
- Неизданные файловые дескрипторы : использование () гарантирует, что все файловые дескрипторы будут освобождены как можно скорее.
- Проблемы с потоками : lock () защищает весь доступ к каждому файлу.
- Различные тома диска : File.Replace () завершается ошибкой при использовании на разных дисковых томах. Мой метод уже проверяет это и возвращается к File.Copy ().
И вот несколько советов, с которыми я столкнулся, и почему я бы не стал их использовать:
- Служба теневого копирования томов : работает только в том случае, если проблемное стороннее программное обеспечение (средства резервного копирования, антивирусные мониторы и т. Д.) Также используют VSS. Использование VSS требует тонны P / Invoke и имеет проблемы с платформой.
- Блокировка файлов : В C # блокировка файла требует сохранения FileStream открытым. Это не позволит использовать стороннее программное обеспечение, но 1) я все равно не смогу заменить файл с помощью File.Replace, и 2) как я уже упоминал выше, я предпочел бы сначала записать во временный файл, чтобы избежать случайного коррупция.
Буду признателен за любую информацию о том, чтобы заставить File.Replace работать каждый раз или, в более общем смысле, надежно сохранять / перезаписывать файлы на диск.