2010-09-01 62 views
8

Tôi đang sử dụng FileSystemWatcher để kiểm tra xem tệp có bị sửa đổi hoặc bị xóa hay không, nhưng tôi tự hỏi liệu có cách nào để kiểm tra xem tệp có được ứng dụng khác đọc hay không.Phát hiện tệp đã đọc trong C#

Ví dụ: Tôi có tệp C: \ test.txt trên đĩa cứng của mình và đang xem tệp bằng FileSystemWatcher. Một chương trình khác (không thuộc quyền kiểm soát của tôi) đi đọc tập tin đó; Tôi muốn nắm bắt sự kiện đó và nếu có thể, hãy kiểm tra xem chương trình nào đang đọc tệp, sau đó sửa đổi nội dung của tệp cho phù hợp.

+1

điều này có vẻ như là một yêu cầu lạ. bạn có thể mở rộng về mục tiêu cuối cùng của bạn nhiều hơn một chút không. – luke

+0

@luke - Những gì tôi muốn làm là mã hóa một phần của tập tin, nhưng khi một ứng dụng web (mà tôi không có quyền kiểm soát) đi đọc tập tin đó tôi sẽ giải mã phần mã hóa cho nó. –

+0

có vẻ như cách tốt hơn để giải quyết vấn đề này là chỉ cần thiết lập kiểm soát truy cập chi tiết hơn để ứng dụng web (và ứng dụng của bạn) có thể đọc tệp, sau đó bạn sẽ không phải mã hóa nó. – luke

Trả lời

4

Có vẻ như bạn muốn ghi vào tệp nhật ký của mình khi tệp nhật ký của bạn được đọc bên ngoài hoặc điều gì đó có hiệu lực. Nếu đúng như vậy, có một giá trị NotifyFilters, LastAccess. Đảm bảo điều này được đặt làm một trong các cờ trong thuộc tính FileSystemWatcher.NotifyFilter của bạn. Thay đổi trong lần truy cập cuối cùng sẽ kích hoạt sự kiện Đã thay đổi trên FileSystemWatcher.

Hiện tại, FileSystemWatcher không cho phép bạn phân biệt trực tiếp giữa đọc và thay đổi; cả hai đều kích hoạt sự kiện đã thay đổi dựa trên "thay đổi" đối với LastAccess. Vì vậy, nó sẽ là không thể xem được cho một số lượng lớn các tập tin. Tuy nhiên, dường như bạn biết tệp nào bạn đang xem, vì vậy nếu bạn có đối tượng FileInfo cho tệp đó và FileSystemWatcher đã kích hoạt sự kiện đã thay đổi của nó, bạn có thể nhận được tệp mới và so sánh giá trị LastAccessTime. Nếu thời gian truy cập thay đổi và LastWriteTime không, tệp của bạn chỉ được đọc. Bây giờ, trong điều kiện đơn giản nhất, những thay đổi bạn thực hiện đối với tệp trong khi tệp đang được đọc sẽ không hiển thị ngay lập tức trong ứng dụng khác, cũng như bạn sẽ không thể "đến đó trước", khóa tệp và viết cho nó trước khi họ nhìn thấy nó. Vì vậy, bạn không thể sử dụng FileSystemWatcher để "chặn" một yêu cầu đọc và hiển thị nội dung bạn muốn ứng dụng đó xem. Cách duy nhất mà người dùng của ứng dụng khác có thể thấy những gì bạn vừa viết là nếu ứng dụng cũng đang xem tệp và tải lại tệp. Điều đó sẽ kích hoạt một sự kiện đã thay đổi khác, gây ra một vòng lặp vô hạn miễn là ứng dụng kia tiếp tục tải lại tệp.

Bạn cũng sẽ nhận được sự kiện đã thay đổi để đọc và viết. Mở một tệp trong trình soạn thảo văn bản (hầu như mọi thứ sẽ làm), thực hiện một số thay đổi, sau đó lưu sẽ kích hoạt hai sự kiện đã thay đổi nếu bạn đang tìm kiếm các thay đổi đối với Lần truy cập cuối cùng. Cái đầu tiên sẽ tắt khi tập tin được mở bởi trình soạn thảo; tại thời điểm đó, bạn có thể không thể nói rằng một ghi sẽ xảy ra, vì vậy nếu bạn đang tìm kiếm truy cập chỉ đọc thuần túy vào tệp thì bạn là SOL.

-2

Một chút snippet mà tôi thấy hữu ích cho việc phát hiện khi quá trình khác có khóa:

static bool IsFileUsedbyAnotherProcess(string filename) 
     { 
      try 
      { 
       using(var file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None)) 
       { 
       } 
      } 
      catch (System.IO.IOException exp) 
      { 
       return true; 
      } 
      return false; 
     } 
+3

Chỉ hoạt động nếu ứng dụng khác đã khóa để ghi. Mở một tệp để đọc không nhất thiết phải khóa nó. – KeithS

+3

Egad! Chức năng đó để tệp mở cho đến khi nó được thu thập rác, có nghĩa là không ai khác có thể mở tệp mà không chia sẻ được bật. – Gabe

+2

Và ai đóng File.Open() ở đây? – kofucii

2

Cách đơn giản nhất tôi có thể nghĩ ra để làm điều này sẽ là một bộ đếm thời gian (System.Threading.Timer) mà kiểm tra callback và lưu trữ các ngoái

System.IO.File.GetLastAccessTime(path) 

Giống như (có thể với khóa hơn một chút ...)

public class FileAccessWatcher 
{ 

public Dictionary<string, DateTime> _trackedFiles = new Dictionary<string, DateTime>(); 

private Timer _timer; 

public event EventHandler<EventArgs<string>> FileAccessed = delegate { }; 

public FileAccessWatcher() 
{ 
    _timer = new Timer(OnTimerTick, null, 500, Timeout.Infinite); 
} 

public void Watch(string path) 
{ 
    _trackedFiles[path] = File.GetLastAccessTime(path); 
} 

public void OnTimerTick(object state) 
{ 
    foreach (var pair in _trackedFiles.ToList()) 
    { 
     var accessed = File.GetLastAccessTime(pair.Key); 
     if (pair.Value != accessed) 
     { 
      _trackedFiles[pair.Key] = accessed; 
      FileAccessed(this, new EventArgs<string>(pair.Key)); 
     } 
    } 

    _timer.Change(500, Timeout.Infinite); 
} 
} 
2

Có chương trình SysInternals 'FileMon ... Nó có thể theo dõi mọi truy cập tệp trong hệ thống. Nếu bạn có thể tìm thấy nguồn của nó, và hiểu những gì win32 móc nó sử dụng, bạn có thể soái các chức năng trong C# và có được những gì bạn muốn.

0

Có, sử dụng trình điều khiển bộ lọc hệ thống tệp bạn có thể nắm bắt tất cả các yêu cầu đọc, phân tích chúng và thậm chí thay thế dữ liệu đang đọc. Việc tự mình phát triển trình điều khiển như vậy là có thể, nhưng rất tốn thời gian và phức tạp. Chúng tôi cung cấp một sản phẩm được gọi là CallbackFilter, bao gồm trình điều khiển sẵn sàng để sử dụng và cho phép bạn triển khai logic kinh doanh lọc của mình ở chế độ người dùng.

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