Sử dụng FileSystemWatcher để giám sát một thư mục


101

Tôi đang sử dụng Ứng dụng Windows Forms để theo dõi một thư mục và di chuyển các tệp được đưa vào thư mục đó sang một thư mục khác.

Tại thời điểm này, nó sẽ sao chép tệp sang một thư mục khác, nhưng khi tệp khác được thêm vào, nó sẽ chỉ kết thúc mà không có thông báo lỗi. Đôi khi nó sao chép hai tệp trước khi kết thúc vào tệp thứ ba.

Điều này có phải do tôi đang sử dụng Ứng dụng Windows Form hơn là ứng dụng bảng điều khiển không? Có cách nào tôi có thể dừng chương trình kết thúc và tiếp tục xem thư mục không?

private void watch()
{
  this.watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += OnChanged;
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}

public void Dispose()
{
  // avoiding resource leak
  watcher.Changed -= OnChanged;
  this.watcher.Dispose();
}

Câu trả lời:


144

Vấn đề là bộ lọc thông báo. Chương trình đang cố gắng mở một tệp vẫn đang sao chép. Tôi đã xóa tất cả các bộ lọc thông báo ngoại trừ LastWrite.

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastWrite;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

6
Xin chào, tôi đang sử dụng phương pháp này nhưng khi tôi sao chép một tệp, sự kiện sẽ xuất hiện hai lần: một lần khi tệp được tạo trống (bắt đầu sao chép) và một lần nữa khi quá trình sao chép kết thúc. Làm thế nào để tránh sự kiện trùng lặp này, bất kỳ bộ lọc nào có thể xử lý nó mà không cần kiểm soát tùy chỉnh điều đó?
dhalfageme

@dhalfageme Tôi kiểm tra cả hai sự kiện nếu bất kỳ sự kiện nào có ý nghĩa đối với ứng dụng của tôi xuất hiện trong thư mục.
Eftekhari

30

Bạn đã không cung cấp mã xử lý tệp, nhưng tôi cho rằng bạn đã mắc phải sai lầm tương tự mà mọi người đều mắc phải khi lần đầu tiên viết một điều như vậy: sự kiện tệp người theo dõi sẽ được đưa ra ngay sau khi tệp được tạo. Tuy nhiên, sẽ mất một khoảng thời gian để hoàn thành tệp. Lấy ví dụ kích thước tệp là 1 GB. Tệp có thể được tạo bởi một chương trình khác (Explorer.exe sao chép nó từ một nơi nào đó) nhưng sẽ mất vài phút để kết thúc quá trình đó. Sự kiện được đưa ra tại thời điểm tạo và bạn cần đợi tệp sẵn sàng được sao chép.

Bạn có thể đợi tệp sẵn sàng bằng cách sử dụng hàm này trong một vòng lặp.


25

Lý do có thể là do watcher được khai báo là biến cục bộ của một phương thức và nó sẽ được thu thập khi phương thức kết thúc. Bạn nên khai báo nó như một thành viên trong lớp. Hãy thử những cách sau:

FileSystemWatcher watcher;

private void watch()
{
  watcher = new FileSystemWatcher();
  watcher.Path = path;
  watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                         | NotifyFilters.FileName | NotifyFilters.DirectoryName;
  watcher.Filter = "*.*";
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
  //Copies file to another directory.
}

18
watcherbiến được giữ nguyên (không được thu gom rác) vì anh ta đã đăng ký sự kiện Đã thay đổi.
adospace

1
Tôi tin rằng đó thực sự là vì EnableRaisingEvents được đặt thành true. Tôi không nghĩ rằng trạng thái của người xử lý sự kiện thành viên liên quan đến việc thu gom rác. Tôi nghĩ rằng EnableRaisingEvents, cái mà tôi có thể ưu ái gọi, một hành vi đặc biệt trong trường hợp này.
Matias Grioni
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.