Предисловие: Я новичок в программировании и в основном самоучка.
Я пишу небольшое приложение, которое автоматически копирует файлы сохранений моей игры в каталог резервных копий. Он использует класс FileSystemWatcher для наблюдения за каталогом сохранения игры и поиска изменений, пока я играю, и вызывает OnChanged, если размер файла изменяется или в него выполняется запись.
Проблема, с которой я столкнулся, заключается в том, что когда моя программа копирует файл, она иногда дает сбой ИГРЫ (в данном случае Terraria). Я предполагаю, что это как-то связано с ограничениями доступа, с которыми у меня нет большого опыта. Я удивлен, что File.Copy () может вызвать проблемы, поскольку он просто читает, но это постоянный сбой с Terraria.
Пошаговое выполнение вызовов OnChanged показало, что Terraria записывает временные файлы, затем копирует их в фактические файлы сохранения и удаляет временные файлы. Довольно часто.
Итак, вот мой код с неуклюжим обходным решением, которое у меня есть. Он использует два таймера: _delayTimer, который запускается при первом вызове OnChanged, и _canBackupTimer, когда истекает _delayTimer. У меня не было проблем с играми, в которых я его тестировал.
Для каждого таймера интервал составляет 5 секунд, а AutoReset = True, поэтому он останавливается по истечении одного раза.
Это единственный способ избежать исключений ввода-вывода при отслеживании игры? Должен быть способ получше, но я не знаю, где искать. Я удивлен, что File.Copy ограничивает доступ к процессу сохранения игры.
Стоит ли смотреть права доступа к файлам?
private static void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
_canBackupTimer.Enabled = true;
_canBackupTimer.Start();
_delayTimer.Enabled = false;
}
private static void _canBackupTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
_lastAutoBackupTime = DateTime.Now;
_canBackupTimer.Enabled = false;
}
private static void OnChanged(object source, FileSystemEventArgs e) {
while (true) {
if (!_canBackupTimer.Enabled && !_delayTimer.Enabled && (DateTime.Now - _lastAutoBackupTime).Seconds > 10) {
//If neither timer is running and 10 seconds
//have elapsed since canBackupTimer stopped
_delayTimer.Enabled = true;
_delayTimer.Start();
continue;
}
if (_canBackupTimer.Enabled) {
//if canBackupTimer is running, do autobackup
Game autoBackupGame = null;
//_gamesToAutoBackup is a List<Game> for the program to watch.
//Check to identify which Game is being backed up
//g.RootFolder is the game's base directory, e.g. "...\Terraria\"
foreach (var g in _gamesToAutoBackup) {
if (e.FullPath.Contains(g.Name) || e.FullPath.Contains(g.RootFolder))
autoBackupGame = g;
}
if (autoBackupGame.RootFolder == null) {
var dir = new DirectoryInfo(autoBackupGame.Path);
autoBackupGame.RootFolder = dir.Name;
}
//Find the base directory of the file being changed and trim off
//the unneeded pieces, e.g. "C:\Users\Rob\..."
var indexOfGamePart = e.FullPath.IndexOf(autoBackupGame.RootFolder);
var friendlyPath = e.FullPath.Substring(0, indexOfGamePart);
var newPath = e.FullPath.Replace(friendlyPath, "\\");
if (Directory.Exists(e.FullPath) && autoBackupGame != null) {
//True if directory, else it's a file.
//Do stuff for backing up a directory here.
//Currently nothing written here.
}
else { //If Directory.Exists is false, the path is a file.
try {
var copyDestinationFullPath = new FileInfo(_specifiedAutoBackupFolder + newPath);
if (!Directory.Exists(copyDestinationFullPath.DirectoryName))
Directory.CreateDirectory(copyDestinationFullPath.DirectoryName);
File.Copy(e.FullPath, copyDestinationFullPath.ToString(), true);
}
catch (FileNotFoundException ex) {
Logger.Log(ex); //My class, Logger, writes the exception text to a file.
}
}
}
break;
}
}