2013-02-11 7 views
10

Mam aplikację, słucham pliku * .log w wybranym folderze. Użyłem FileSystemWatcher.Jak czekać do File.Exists?

Ale jest problem. Druga aplikacja odpowiedzialna za dokonywanie że plik ma następujące etapy:

  1. Złóż a * .gz plik
  2. rozpakuj go do pliku txt (jakiś przypadkowy nazwa pliku)
  3. Zmienianie * .txt nazwisko do prawidłowego jednego z rozszerzeniem * .log.

Nie mogę zmienić tego zachowania.

Zrobiłem 2 FileSystemWatcher s dla plików * .gz i * .txt. Czemu? Ponieważ ta aplikacja czasami nie rozpakowuje pliku gz, a czasami nie zmienia nazwy pliku txt na ostateczny plik * .log.

FileSystemWatcher2 przechwytuje plik txt, a następnie (w większości przypadków jest przemianowany na logowanie kolejnych 1000ms) Potrzebuję trochę czasu, aby sprawdzić, czy plik txt istnieje (jeśli nie, to wydaje się, że zmieniono jego nazwę na ostateczny * .plik dziennika).

Pytanie brzmi, jak sprawdzić, czy plik istnieje bez Thread.Sleep(), aby zapobiec zawieszaniu się interfejsu użytkownika?

Mam nadzieję, że jest jasne, jeśli nie, spróbuję opisać to lepiej. Myślę, że to skomplikowany problem.

Niektóre przykładowy kod:

Watcher dla pliku gz:

private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e) 
{ 
    //this is for gz files in case if gz file is not unpacked automatically by other app 
    //I need to wait and check if gz was unpacked, if not, unpack it by myself, 
    //then txt watcher will catch that 
    Thread.Sleep(5000); 
    if (File.Exists(e.FullPath)) 
    { 
     try 
     { 
     byte[] dataBuffer = new byte[4096]; 
     using (System.IO.Stream fs = new FileStream(e.FullPath, 
                FileMode.Open, 
                FileAccess.Read)) 
     { 
      using (GZipInputStream gzipStream = new GZipInputStream(fs)) 
      {        
       string fnOut = Path.Combine(path_to_watcher, 
              Path.GetFileNameWithoutExtension(e.FullPath)); 

       using (FileStream fsOut = File.Create(fnOut)) 
       { 
        StreamUtils.Copy(gzipStream, fsOut, dataBuffer); 
       }        
      } 
     } 
     } 
     catch { //Ignore } 
    } 
} 

Watcher do pliku txt:

private void fileSystemWatcher2_Created(object sender, FileSystemEventArgs e) 
{ 
    //this is for txt file 
    Thread.Sleep(3500); 
    if (File.Exists(e.FullPath)) 
    { 
     //make my actions 
    } 
    else 
    { 
     //make my actions 
    } 
} 
+0

Wszystko 'Thread.Sleep()' robi jest zrezygnować z wątku zwolnić zasoby komputera jest za pomocą tak, że mogą one być wykorzystywane do innych zadań.Nie jest to idealne rozwiązanie w przypadku niektórych scenariuszy (ponieważ ma minimalną ziarnistość 1 ms), ale do tego, co próbujesz osiągnąć, może działać dobrze. –

+0

@RobertHarvey Czy masz dokumentację do tego? Z mojego doświadczenia wynika, że ​​Thread.Sleep powstrzymuje wątek przed przetwarzaniem dalszych instrukcji do upływu czasu. Z MSDN: 'Wątek nie zostanie zaplanowany do wykonania przez system operacyjny na określony czas. – CodingGorilla

+0

@CodingGorilla: Tak, zgadza się. Blokuje i zwalnia zasoby, które wątek trzyma dla innych zadań. Zasadniczo mówi: "Nic nie robię przez następne n milisekund, więc możesz odejść i zrobić coś innego w tym czasie." –

Odpowiedz

1

Można użyć snu bez blokowania wątku UI, to w zasadzie spać oddzielny wątek.

public event EventHandler FileCreated; 
public void CheckFileExists() 
{ 
    while(!File.Exists("")) 
    { 
    Thread.Sleep(1000); 
    } 
    FileCreated(this, new EventArgs()); 
} 

Następnie nazwać to jako:

Thread t = new Thread(CheckFileExists); 
this.FileCreated += new EventHandler(somemethod); 
t.Start(); 

public void SomeMethod(object sender, EventArgs e) 
{ 
    MessageBox.Show("File Created!"); 
} 

Albo jak wspomniano w innym poście użyć BackGroundWorker w miejscu gwintu indywidualne, umieścić kod wspomniałem w DoWork i nasłuchiwać OnFinish imprezy, ale widząc, jak nie ma zbyt wiele pracy do zrobienia, obie metody są w porządku.

+0

Jest to prawdopodobnie lepiej obsługiwane przez 'Task' lub' ThreadPool.QueueUserWorkItem'. – CodingGorilla

+0

@CodingGorilla Oczywiście byłoby to zależne od ram OP dla zadania, ale tak, prawdopodobnie masz rację: P – LukeHennerley

+0

OK, dziękuję za pomysły. Sprawdzę je. Jest mega pomocny – user1750355

3

Można użyć BackGroundWorker do monitorowania systemu plików - i unikać zamrażania Twój UI

7

Właściwie FileSystemWatcher Utworzono wydarzenie nazywane w osobnym wątku przez .NET samego .. Więc w zasadzie trzeba zrobić absolutnie nic . Twój kod jest OK.

Oto dowód:

class Program 
{ 
    static void Main(string[] args) 
    { 
     FileSystemWatcher fw = new FileSystemWatcher(@"C:\temp"); 
     fw.Created += fileSystemWatcher_Created; 

     Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 

     fw.EnableRaisingEvents = true; 

     Console.ReadLine(); 
    } 

    static void fileSystemWatcher_Created(object sender, FileSystemEventArgs e) 
    { 
     Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
    } 
}