Обнаружить чтение файла в C#

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

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


person Petey B    schedule 01.09.2010    source источник
comment
это кажется странным требованием. Вы можете немного подробнее рассказать о своей конечной цели.   -  person luke    schedule 02.09.2010
comment
@luke - Что я хотел бы сделать, так это зашифровать часть файла, но когда веб-приложение (которое я не могу контролировать) переходит к чтению этого файла, я расшифровываю для него зашифрованную часть.   -  person Petey B    schedule 02.09.2010
comment
кажется, что лучшим способом решить эту проблему было бы просто настроить более точный контроль доступа, чтобы только веб-приложение (и ваше приложение) могло читать файл, тогда вам вообще не нужно было бы его шифровать.   -  person luke    schedule 02.09.2010


Ответы (6)


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

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

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

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

person KeithS    schedule 01.09.2010

Самый простой способ сделать это — использовать таймер (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);
}
}
person Jeff    schedule 01.09.2010

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

person alxx    schedule 01.09.2010

Вы можете использовать FileInfo.LastAccessTime и FileInfo.Refresh() в цикле опроса.

http://msdn.microsoft.com/en-us/library/system.io.fileinfo_members.aspx

person Jonathan S.    schedule 01.09.2010

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

person Eugene Mayevski 'Callback    schedule 02.09.2010

Небольшой фрагмент, Я нашел полезным определить, когда другой процесс имеет блокировку:

 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; 
        }
person John M    schedule 01.09.2010
comment
Работает только в том случае, если другое приложение заблокировало его для записи. Открытие файла для чтения не обязательно блокирует его. - person KeithS; 02.09.2010
comment
Эгад! Эта функция оставляет файл открытым до тех пор, пока он не будет удален сборщиком мусора, а это означает, что никто другой не сможет открыть его без включения общего доступа. - person Gabe; 02.09.2010
comment
А кто здесь закрывает File.Open()? - person kofucii; 02.09.2010
comment
Добавлено «использование», чтобы оно очищалось после себя, и к файлу можно было получить доступ после выхода из функции. - person Grant Peters; 13.06.2014