2010-02-09 16 views
10

Mam system plików, który uruchomi zdarzenie, gdy plik zostanie zmodyfikowany. Chcę przeczytać z tego pliku po usunięciu blokady. W tej chwili próbuję otworzyć plik po uruchomieniu zdarzenia. Podczas kopiowania dużego pliku blokada pliku pozostaje włączona przez pewien czas po wysłaniu zdarzeń, uniemożliwiając otwarcie pliku w celu uzyskania dostępu do odczytu.Wyzwalacze FileSystemWatcher dla strumienia plików otwarte

Wszelkie sugestie?

Odpowiedz

6

Ten jest właściwie odrobiną dozy, chyba że przestrzeń problemu zmieniła się znacząco od czasu, gdy ostatnio musiałem sobie z tym poradzić.

Najprostszym sposobem jest po prostu spróbuj otworzyć plik, przechwycić wynikowy plik IOException, a jeśli plik jest zablokowany, dodaj go do kolejki, aby później sprawdzić. Nie możesz po prostu sprobować przetwarzać każdego przychodzącego pliku, ponieważ istnieją różne rodzaje przypadków, w których generowane są różne zdarzenia dla tego samego pliku, więc ustawienie pętli ponownej próby dla każdego odebranego zdarzenia może szybko przekształcić się w katastrofę. Zamiast tego należy je umieścić w kolejce i regularnie sprawdzać kolejkę.

Oto podstawowe klasy szablon, który powinien pomóc z tym problemem:

public class FileMonitor : IDisposable 
{ 
    private const int PollInterval = 5000; 

    private FileSystemWatcher watcher; 
    private HashSet<string> filesToProcess = new HashSet<string>(); 
    private Timer fileTimer; // System.Threading.Timer 

    public FileMonitor(string path) 
    { 
     if (path == null) 
      throw new ArgumentNullException("path"); 

     watcher = new FileSystemWatcher(); 
     watcher.Path = path; 
     watcher.NotifyFilter = NotifyFilters.FileName; 
     watcher.Created += new FileSystemEventHandler(FileCreated); 
     watcher.EnableRaisingEvents = true; 

     fileTimer = new Timer(new TimerCallback(ProcessFilesTimer), 
      null, PollInterval, Timeout.Infinite); 
    } 

    public void Dispose() 
    { 
     fileTimer.Dispose(); 
     watcher.Dispose(); 
    } 

    private void FileCreated(object source, FileSystemEventArgs e) 
    { 
     lock (filesToProcess) 
     { 
      filesToProcess.Add(e.FullPath); 
     } 
    } 

    private void ProcessFile(FileStream fs) 
    { 
     // Your code here... 
    } 

    private void ProcessFilesTimer(object state) 
    { 
     string[] currentFiles; 
     lock (filesToProcess) 
     { 
      currentFiles = filesToProcess.ToArray(); 
     } 
     foreach (string fileName in currentFiles) 
     { 
      TryProcessFile(fileName); 
     } 
     fileTimer.Change(PollInterval, Timeout.Infinite); 
    } 

    private void TryProcessFile(string fileName) 
    { 
     FileStream fs = null; 
     try 
     { 
      FileInfo fi = new FileInfo(fileName); 
      fs = fi.OpenRead(); 
     } 
     catch (IOException) 
     { 
      // Possibly log this error 
      return; 
     } 

     using (fs) 
     { 
      ProcessFile(fs); 
     } 

     lock (filesToProcess) 
     { 
      filesToProcess.Remove(fileName); 
     } 
    } 
} 

(Uwaga - Ja przypominając to z pamięci tutaj, więc nie może być doskonały - daj mi znać, jeśli jest wadliwy .)

+0

Dobrze, właśnie z tym poszedłem, czekając. Użyłem limitu czasowego i ponownego oczekiwania, miałem nadzieję, że było coś bardziej eleganckiego, ale no cóż;) (Dzięki za milion wysiłku za wspaniałą odpowiedź) – Matthew

Powiązane problemy