【问题标题】:Detect File Read in C#在 C# 中检测文件读取
【发布时间】:2010-09-01 19:55:54
【问题描述】:

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

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

【问题讨论】:

  • 这似乎是一个奇怪的要求。您能否进一步扩展您的最终目标。
  • @luke - 我想做的是加密文件的一部分,但是当 Web 应用程序(我无法控制)去读取该文件时,我将解密加密的部分它。
  • 似乎解决这个问题的更好方法是设置更细粒度的访问控制,以便只有网络应用程序(和您的应用程序)可以读取文件,然后您就不会完全加密它。

标签: c# file-io filesystemwatcher


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案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);
    }
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            我发现一点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; 
                    }
            

            【讨论】:

            • 只有在其他应用程序锁定它以进行写入时才有效。打开文件读取并不一定会锁定它。
            • 埃加德!该功能使文件保持打开状态,直到它被垃圾收集,这意味着没有启用共享的情况下没有其他人可以打开它。
            • 谁在这里关闭 File.Open()?
            • 添加了一个'using',这样它就可以自行清理,并且在函数退出后可以访问文件。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-11-19
            • 1970-01-01
            • 2013-03-19
            • 2016-05-31
            • 1970-01-01
            相关资源
            最近更新 更多