web-dev-qa-db-ja.com

File.Existsまで待つ方法は?

選択したフォルダーで* .logファイルをリッスンするアプリがあります。 FileSystemWatcherを使用しました。

しかし問題がある。そのファイルの作成を担当する他のアプリは、次の手順を実行します。

  1. * .gzファイルを作成します
  2. Txtファイル(ランダムなファイル名)に解凍します
  3. * .txt名を* .log拡張子の付いた適切な名前に変更します。

そして、私はこの振る舞いを変えることはできません。

そこで、*。gzファイルと* .txtファイル用に2つのFileSystemWatchersを作成しました。どうして?このアプリはgzファイルを解凍しない場合や、txtファイルの名前を最終的な* .logファイルに変更しない場合があるためです。

_FileSystemWatcher2_はtxtファイルをキャッチし、(ほとんどの場合、次の1000ミリ秒でログインするように名前が変更されます)txtファイルが存在するかどうかを確認するためにしばらく待つ必要があります(存在しない場合は、最後の名前に変更されているようです* .logファイル)。

問題は、UIのフリーズを防ぐためにThread.Sleep()なしでファイルが存在するかどうかを確認する方法です。

私はそれが明確であることを願っています、そうでなければ私はそれをよりよく説明しようとします。これは複雑な問題だと思います。

いくつかのコードサンプル:

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 }
   }
}
_

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
   }
}
_
14
user1750355

実際には、FileSystemWatcher。NET自体によって別のスレッドで呼び出される作成されたイベント..したがって、基本的にまったく何もする必要はありません。あなたのコードはそのままでOKです。

これがその証拠です:

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);
    }
}
9
Boppity Bop

BackGroundWorker を使用してファイルシステムを監視し、UIのフリーズを回避できます

3
Dave Bish

UIスレッドをロックせずにスリープを使用できます。基本的に、別のスレッドをスリープします。

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

次に、これを次のように呼び出します。

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

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

または、別の投稿で言及されているように、別のスレッドの代わりにBackGroundWorkerを使用し、言及したコードをDoWorkに入れて、OnFinishイベントをリッスンしますが、ないので確認しますどちらの方法でも、それだけの作業で問題ありません。

2
LukeHennerley
int i = 0;
while (!File.Exists && i < 30) //limit the time to whait to 30 sec
{
    Threed.Sleep(1000);
    File.Refresh();
    i++;
}
0
Tamir Reiss