2013-07-01 38 views
9

Cách nào là cách sạch nhất để await để tệp được tạo bởi ứng dụng bên ngoài?Không đồng bộ chờ tệp được tạo

async Task doSomethingWithFile(string filepath) 
    { 
     // 1. await for path exists 
     // 2. Do something with file 
    } 

Trả lời

12

Vì vậy, điểm mấu chốt đầu tiên là bạn có thể sử dụng FileSystemWatcher để được thông báo khi sự kiện hệ thống tệp thay đổi ở một đường dẫn cụ thể. Ví dụ: nếu bạn muốn được thông báo khi tệp được tạo tại một vị trí cụ thể, bạn có thể tìm hiểu.

Tiếp theo, chúng ta có thể tạo phương thức sử dụng TaskCompletionSource để kích hoạt hoàn thành tác vụ khi trình theo dõi hệ thống tệp kích hoạt sự kiện có liên quan.

public static Task WhenFileCreated(string path) 
{ 
    if (File.Exists(path)) 
     return Task.FromResult(true); 

    var tcs = new TaskCompletionSource<bool>(); 
    FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path)); 

    FileSystemEventHandler createdHandler = null; 
    RenamedEventHandler renamedHandler = null; 
    createdHandler = (s, e) => 
    { 
     if (e.Name == Path.GetFileName(path)) 
     { 
      tcs.TrySetResult(true); 
      watcher.Created -= createdHandler; 
      watcher.Dispose(); 
     } 
    }; 

    renamedHandler = (s, e) => 
    { 
     if (e.Name == Path.GetFileName(path)) 
     { 
      tcs.TrySetResult(true); 
      watcher.Renamed -= renamedHandler; 
      watcher.Dispose(); 
     } 
    }; 

    watcher.Created += createdHandler; 
    watcher.Renamed += renamedHandler; 

    watcher.EnableRaisingEvents = true; 

    return tcs.Task; 
} 

Lưu ý rằng lần đầu tiên kiểm tra xem tệp có tồn tại hay không, để cho phép nó thoát ngay lập tức nếu có. Nó cũng sử dụng cả trình xử lý được tạo và đổi tên vì một trong hai tùy chọn có thể cho phép tệp tồn tại tại một số điểm trong tương lai. Các FileSystemWatcher cũng chỉ xem các thư mục, vì vậy điều quan trọng là để có được thư mục của đường dẫn được chỉ định và sau đó kiểm tra tên tệp của từng tệp bị ảnh hưởng trong trình xử lý sự kiện.

Cũng lưu ý rằng mã sẽ xóa trình xử lý sự kiện khi hoàn tất.

Điều này cho phép chúng tôi viết:

public static async Task Foo() 
{ 
    await WhenFileCreated(@"C:\Temp\test.txt"); 
    Console.WriteLine("It's aliiiiiive!!!"); 
} 
+0

Liệu WhenFileCreated có hoàn thành nếu đường dẫn đã tồn tại? –

+0

@AlexS No. Bạn có thể kiểm tra điều đó ở đầu phương thức để xử lý trường hợp đó mặc dù chỉ với một dòng mã. – Servy

+1

Nếu tên tệp được chỉnh sửa thì sao? Ngoài ra, anh ấy muốn chờ một tên tập tin cụ thể. –

-4

Đây là cách tôi muốn làm điều đó:

await Task.Run(() => {while(!File.Exists(@"yourpath.extension")){} return;}); 
//do all the processing 

Bạn cũng có thể gói nó vào một phương pháp:

public static Task WaitForFileAsync(string path) 
{ 
    if (File.Exists(path)) return Task.FromResult<object>(null); 
    var tcs = new TaskCompletionSource<object>(); 
    FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path)); 
    watcher.Created += (s, e) => 
    { 
     if (e.FullPath.Equals(path)) 
     { 
      tcs.TrySetResult(null); 
      if (watcher != null) 
      { 
       watcher.EnableRaisingEvents = false; 
       watcher.Dispose(); 
      } 
     } 
    }; 
    watcher.Renamed += (s, e) => 
    { 
     if (e.FullPath.Equals(path)) 
     { 
      tcs.TrySetResult(null); 
      if (watcher != null) 
      { 
       watcher.EnableRaisingEvents = false; 
       watcher.Dispose(); 
      } 
     } 
    }; 
    watcher.EnableRaisingEvents = true; 
    return tcs.Task; 
} 

và sau đó chỉ cần sử dụng nó như thế này:

await WaitForFileAsync("yourpath.extension"); 
//do all the processing 
+4

-1 cho bận rộn-chờ đợi. –

+0

@StephenCleary Vâng, không có FileExistsAsync ở đó? 'FileSystemWatcher' có thể cung cấp cho bạn tên đường dẫn sai và không phải lúc nào cũng bao gồm các tên hoặc nếu tệp tồn tại. Đây có lẽ là cách tốt nhất. –

+0

@StephenCleary Anyways, đã cố gắng khắc phục. –

Các vấn đề liên quan