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