Wyobraźmy sobie hipotetyczną sytuację:
- Program A zapisuje dane do pliku blokując go dla innych programów
- Program B próbuje odczytać dane z zablokowanego pliku i ... BUUUUM!!!
- Program B transferujący dane do lotniskowca przerywa działanie.
- Kapitan podejrzewając wrogi atak na bazę odpala rakiety ziemia-powietrze w kierunkach strategicznych.
- Zaczyna się III wojna światowa......
Rozwiązaniem umożliwiającym uratowanie świata przed zagładą jest metoda wyczekującą na odblokowanie pliku.
Inicjujemy zmienną typu AutoResetEvent, która zajmuje się zatrzymywaniem wątku.
Inicjujemy obiekt typu FileSystemWatcher, nasłuchujący zmian katalogu zawierającym nasz plik.
Poniżej cały, kod funkcji dla tych, którzy już od zaraz chcą ratować świat :)
Inicjujemy zmienną typu AutoResetEvent, która zajmuje się zatrzymywaniem wątku.
var autoResetEvent = new AutoResetEvent(false);Próbujemy otworzyć plik poleceniem File.Open, jeśli nam się to uda to robimy z plikiem to co chcemy i hasta la vista, baby.
using (FileStream file = File.Open(path, fm, fa, fs)) { action(file); break; }Całe rozwiązanie znajdujemy w sytuacji kiedy plik jest zablokowany i dostajemy wyjątek IOException.
Inicjujemy obiekt typu FileSystemWatcher, nasłuchujący zmian katalogu zawierającym nasz plik.
var fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(path)) { EnableRaisingEvents = true };Zatrzymujemy wątek w oczekiwaniu na odblokowanie pliku:
autoResetEvent.WaitOne();Gdy plik zostanie już odblokowany autoResetEvent ponownie uruchomi działanie wątku:
autoResetEvent.Set();i cała operacja zacznie się od początku.
Poniżej cały, kod funkcji dla tych, którzy już od zaraz chcą ratować świat :)
public static void OpenIfNotLocked(string path, Action<FileStream> action, FileMode fm = FileMode.OpenOrCreate, FileAccess fa = FileAccess.ReadWrite, FileShare fs = FileShare.None) { var autoResetEvent = new AutoResetEvent(false); while (true) { try { using (FileStream file = File.Open(path, fm, fa, fs)) { action(file); break; } } catch (IOException) { var fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(path)) { EnableRaisingEvents = true }; fileSystemWatcher.Changed += (o, e) => { if (Path.GetFullPath(e.FullPath) == Path.GetFullPath(path)) { autoResetEvent.Set(); } }; autoResetEvent.WaitOne(); } } }
Brak komentarzy:
Prześlij komentarz