2010-09-01 3 views
8

Я использую FileSystemWatcher, чтобы проверить, когда файл изменен или удален, но мне интересно, есть ли способ проверить, когда файл читается другим приложением.Обнаружение файла, прочитанного на C#

Пример: У меня есть файл C: \ test.txt на моем жестком диске и я смотрю его с помощью FileSystemWatcher. Другая программа (не под моим контролем) идет на чтение этого файла; Я хотел бы поймать это событие и, если возможно, проверить, какая программа читает файл, затем соответствующим образом изменить содержимое файла.

+1

Это кажется странным требованием. можете ли вы расширить свою конечную цель? – luke

+0

@ luke - Что я хотел бы сделать, так это зашифровать часть файла, но когда веб-приложение (которое я не контролирую) переходит к чтению этого файла, я расшифрую зашифрованную часть для него. –

+0

кажется, что лучший способ решить это - просто настроить более мелкозернистый контроль доступа, чтобы только веб-приложение (и ваше приложение) могло читать файл, тогда вам вообще не понадобилось бы его зашифровывать. – luke

ответ

4

Похоже, вы хотите записать в файл журнала, когда ваш файл журнала читается извне или что-то в этом роде. Если это так, есть значение NotifyFilters, LastAccess. Убедитесь, что этот параметр установлен как один из флагов в свойстве FileSystemWatcher.NotifyFilter. Изменение последнего времени доступа приведет к запуску события «Изменено» в FileSystemWatcher.

В настоящее время FileSystemWatcher не позволяет напрямую дифференцировать чтение и изменение; они оба запускают событие Changed, основанное на «изменении» на LastAccess. Таким образом, было бы невозможно наблюдать за чтением большого количества файлов. Тем не менее, вы, кажется, знаете, какой файл вы смотрите, поэтому, если у вас есть объект FileInfo для этого файла, а FileSystemWatcher выпустил событие Changed, вы можете получить новый и сравнить значения LastAccessTime. Если время доступа изменилось, а LastWriteTime - нет, ваш файл будет только прочитан.

Теперь, в простейших условиях, изменения, внесенные вами в файл во время его чтения, не будут отображаться сразу в другом приложении, и вы не сможете «попасть туда первым», заблокировать файл и напишите ему, прежде чем они это видят. Таким образом, вы не можете использовать FileSystemWatcher для «перехвата» запроса на чтение и отображения содержимого, которое вы хотите видеть в этом приложении. Единственный способ, которым пользователь другого приложения может видеть то, что вы только что написали, - это приложение, которое также просматривает файл и перезагружает файл. Это запустит другое событие Changed, вызывая бесконечный цикл, пока другое приложение продолжает перезагружать файл.

Вы также получите событие Changed для чтения и записи. Открытие файла в текстовом редакторе (практически любой будет), внесение некоторых изменений, а затем сохранение приведет к пожару двух Измененных событий, если вы ищете изменения в режиме последнего доступа. Первый будет отключен, когда файл откроется редактором; в то время вы не сможете сказать, что запись произойдет, поэтому, если вы ищете чистые доступа только для чтения к файлу, вы являетесь SOL.

-2

Немного snippet, что я нашел полезным для обнаружения, когда другой процесс имеет блокировку:

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

Работает только в том случае, если другое приложение заблокировало его для записи. Открытие файла для чтения не обязательно блокирует его. – KeithS

+3

Egad! Эта функция оставляет файл открытым до тех пор, пока он не получит сбор мусора, а это означает, что никто не может его открыть без совместного использования. – Gabe

+2

И кто закрывает File.Open() здесь? – kofucii

2

Самый простой способ, которым я могу думать, чтобы сделать это было бы с таймером (System.Threading.Timer) которого обратный вызов проверки и сохраняет последний

System.IO.File.GetLastAccessTime(path) 

Что-то вроде (возможно, с немного больше замок ...)

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

Существует программа Sysinternals' FileMon ... Он может проследить каждый доступ к файлам в системе. Если вы можете найти его источник и понять, что использует перехватчики win32, вы можете объединить эти функции на C# и получить то, что хотите.

0

Да, используя драйвер фильтра файловой системы, вы можете поймать все запросы на чтение, проанализировать их и даже заменить прочитанные данные. Разработка такого драйвера сама по себе возможна, но очень трудоемкая и сложная. Мы предлагаем продукт под названием CallbackFilter, который включает в себя готовый к использованию драйвер и позволяет реализовать вашу бизнес-логику фильтрации в пользовательском режиме.

Смежные вопросы