8

我正在使用 FileSystemWatcher 检查文件何时被修改或删除,但我想知道是否有任何方法可以检查文件何时被另一个应用程序读取。

示例:我的硬盘上有文件 C:\test.txt,并且正在使用 FileSystemWatcher 观看它。另一个程序(不在我的控制之下)去读取那个文件;我想捕捉那个事件,如果可能的话,检查什么程序正在读取文件,然后相应地修改文件的内容。

4

6 回答 6

4

听起来您想在外部读取日志文件时写入日志文件,或者类似的东西。如果是这种情况,则有一个 NotifyFilters 值 LastAccess。确保将其设置为 FileSystemWatcher.NotifyFilter 属性中的标志之一。最后访问时间的更改将触发 FileSystemWatcher 上的 Changed 事件。

目前,FileSystemWatcher 不允许您直接区分读取和更改;他们都根据对 LastAccess 的“更改”触发 Changed 事件。因此,监视对大量文件的读取是不可行的。但是,您似乎知道您正在观看哪个文件,因此如果您有该文件的 FileInfo 对象,并且 FileSystemWatcher 触发了其 Changed 事件,您可以获得一个新的并比较 LastAccessTime 值。如果访问时间改变了,而 LastWriteTime 没有改变,那么你的文件只是被读取。

现在,简单来说,您在读取文件时对文件所做的更改不会立即显示在其他应用程序中,您也无法“先到达那里”、锁定文件并写入文件在他们看到之前。因此,您不能使用 FileSystemWatcher 来“拦截”读取请求并显示您希望该应用程序看到的内容。另一个应用程序的用户可以看到您刚刚编写的内容的唯一方法是该应用程序是否也在监视该文件并重新加载该文件。这将触发另一个 Changed 事件,只要其他应用程序继续重新加载文件,就会导致无限循环。

您还将获得一个用于读取和写入的 Changed 事件。如果您正在寻找对上次访问时间的更改,则在文本编辑器中打开文件(几乎任何都可以),进行一些更改,然后保存将触发两个 Changed 事件。当编辑器打开文件时,第一个将熄灭;那时,您可能无法判断是否会发生写入,因此如果您正在寻找对文件的纯只读访问,那么您就是 SOL。

于 2010-09-01T20:37:35.497 回答
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);
}
}
于 2010-09-01T20:13:08.440 回答
2

有SysInternals的程序FileMon...它可以跟踪系统中的每一个文件访问。如果您能找到它的源代码,并了解它使用了哪些 win32 挂钩,您可能会在 C# 中编组这些函数并获得您想要的。

于 2010-09-01T20:16:32.060 回答
1

您可以在轮询循环中使用 FileInfo.LastAccessTime 和 FileInfo.Refresh()。

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

于 2010-09-01T20:09:15.427 回答
0

是的,使用文件系统过滤器驱动程序,您可以捕获所有读取请求、分析它们甚至替换正在读取的数据。自己开发这种驱动程序是可能的,但非常耗时且复杂。我们提供了一个名为CallbackFilter的产品,它包括一个现成的驱动程序,让您可以在用户模式下实现您的过滤业务逻辑。

于 2010-09-02T09:33:16.683 回答
-2

我发现一个小片段对检测另一个进程何时有锁很有用:

 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; 
        }
于 2010-09-01T20:04:33.850 回答