2012-02-20 34 views
13

Tôi gặp sự cố với danh sách tệp làm mới sau khi xóa tệp. Khi tôi đưa ra lệnh xóa tệp, ngoại lệ đã được ném vì phương thức làm mới đã cố gắng truy cập vào tệp được cho là đã bị xóa.Đang chờ hệ thống xóa tệp

Sau khi suy nghĩ và gỡ lỗi, tôi đã kết luận rằng vấn đề là trong thực tế là hệ thống cần một chút thời gian để xóa một tệp. Và tôi giải quyết nó như sau:

//Deleting file 
System.Threading.Thread.Sleep(2000); 
//Refreshing list 

và nó hoạt động tốt.

Câu hỏi của tôi là

Có cách thanh lịch hơn để chờ đợi cho hệ thống làm file để xóa và sau đó tiếp tục với mã ...?

+1

Chúng ta có thể nhìn thấy phần còn lại của mã? Ngoài ra, loại hệ thống tập tin (địa phương NTFS hoặc một số hình thức của NFS)? Hầu hết các hoạt động xóa hệ thống tập tin, trên NTFS anyway, là nguyên tử. –

+0

Trên NTFS. Phần nào của mã mà bạn quan tâm. Xóa phương thức đệ quy xóa tất cả các tệp trong thư mục và chính thư mục đó. Tôi đã không nghĩ rằng đó là có liên quan vì vậy tôi nói rằng tôi cần phải xóa một tập tin ... Đó là điều tương tự, phải không? – kr85

+1

Không hề.Tôi sẽ để lại câu trả lời –

Trả lời

5

Cách thanh lịch nhất mà tôi có thể nghĩ đến là sử dụng FileSystemWatcher và đăng ký sự kiện Deleted của nó.

+3

Nếu đây là một phân vùng NFS, như tôi nghi ngờ, thì FileSystemWatcher có thể không đáng tin cậy: http://stackoverflow.com/questions/239988/filesystemwatcher-vs-polling-to-watch-for-changes –

+1

@ChrisShain Tôi chỉ sử dụng nó trên một hệ thống NTFS và nó hoạt động rất tốt. Không chắc chắn về NFS mặc dù – GETah

+0

Giải pháp quá phức tạp, tôi giả định – Beatles1692

1

Xóa thư mục bằng cách sử dụng Directory.Delete, cụ thể là the overload that takes a 'recursive' boolean, trên NTFS, phải là hoạt động nguyên tử từ góc độ chương trình của bạn. Không cần tự mình tái sử dụng.

+0

Nó phải là, nhưng nó không phải là. Directory.Exists đôi khi sẽ trả về true, đặc biệt là khi nó là dòng tiếp theo. Tệ hơn, Directory.Create đôi khi sẽ ném khi được gọi đến một cách nhanh chóng sau khi Directory.Delete. – ILMTitan

0

Directory.Delete sẽ ném một ngoại lệ vào lỗi đầu tiên mà nó gặp phải. Nếu bạn muốn tiếp tục xóa bao nhiêu tệp và thư mục con như bạn có thể thì bạn không nên sử dụng Directory.Delete và nên viết xóa đệ quy của riêng bạn bằng các khối try/catch bên trong các vòng lặp. Một ví dụ khi bạn có thể muốn làm điều đó là nếu bạn đang cố gắng dọn dẹp các tệp tạm thời và một trong các tệp đã bị khóa.

1

Dưới đây là một số mã sử dụng FileWatcher. Những gì chúng ta muốn có thể làm là

await Utils.DeleteDirectoryAsync("c:\temp\foo", recurse: true); 

dưới đây thực hiện nó

using System; 
using System.IO; 
using System.Reactive; 
using System.Reactive.Linq; 
using System.Reactive.Subjects; 
using System.Threading.Tasks; 

namespace Utils 
{ 
    internal class FileWatcher : IDisposable 
    { 
     readonly FileSystemWatcher _Watcher; 

     public Subject<FileSystemEventArgs> Changed = new Subject<FileSystemEventArgs>(); 

     public FileWatcher(string file) 
     { 
      // Create a new FileSystemWatcher and set its properties. 
      _Watcher = new FileSystemWatcher 
         { 
          Path = Path.GetDirectoryName(file), 
          NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
              | NotifyFilters.FileName | NotifyFilters.DirectoryName, 
          Filter =Path.GetFileName(file) 
         }; 

      // Add event handlers. 
      _Watcher.Changed += OnChanged; 
      _Watcher.Created += OnChanged; 
      _Watcher.Deleted += OnChanged; 
      _Watcher.Renamed += OnChanged; 

      // Begin watching. 
      _Watcher.EnableRaisingEvents = true; 
     } 

     // Define the event handlers. 
     private void OnChanged(object source, FileSystemEventArgs e) 
     { 
      Changed.OnNext(e); 
     } 


     public void Dispose() 
     { 
      _Watcher.Dispose(); 
     } 
    } 
} 

và một số utils rằng tận dụng các quan sát được ở trên.

public static class FileUtils 
{ 
    public static IObservable<FileSystemEventArgs> ChangedObservable(string path) 
    { 
     if (path == null) 
      return Observable.Never<FileSystemEventArgs>(); 

     return Observable.Using(() => new FileWatcher(path), watcher => watcher.Changed); 
    } 

    public static Task DeleteDirectoryAsync(string path, bool recurse) 
    { 
     var task = new TaskCompletionSource<Unit>(); 

     if (Directory.Exists(path)) 
     { 
      ChangedObservable(path) 
       .Where(f => f.ChangeType == WatcherChangeTypes.Deleted) 
       .Take(1) 
       .Subscribe(v => task.SetResult(Unit.Default)); 

      Directory.Delete(path, recurse); 
     } 
     else 
     { 
      task.SetResult(Unit.Default); 
     } 

     return task.Task; 
    } 
} 
9

này làm việc cho tôi:

public static void DeleteFile(String fileToDelete) 
{ 
    var fi = new System.IO.FileInfo(fileToDelete); 
    if (fi.Exists) 
    { 
     fi.Delete(); 
     fi.Refresh(); 
     while (fi.Exists) 
     { System.Threading.Thread.Sleep(100); 
      fi.Refresh(); 
     } 
    } 
} 

tôi thấy rằng hầu hết thời gian, vòng lặp while sẽ không được nhập vào.

2

Mã nhẹ để sử dụng số FileSystemWatcher, đăng ký sự kiện Deleted và chờ.

void DeleteFileAndWait(string filepath, int timeout = 30000) 
{ 
    using (var fw = new FileSystemWatcher(Path.GetDirectoryName(filepath), Path.GetFileName(filepath))) 
    using (var mre = new ManualResetEventSlim()) 
    { 
     fw.EnableRaisingEvents = true; 
     fw.Deleted += (object sender, FileSystemEventArgs e) => 
     { 
      mre.Set(); 
     }; 
     File.Delete(filepath); 
     mre.Wait(timeout); 
    } 
} 
0

tôi luôn luôn sử dụng này:

System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); 

Xem herehere

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