如何监控Windows目录的变化?

36

当Windows系统中的目录发生更改时,我需要立即通知一个程序。

是否有一种方法可以在更改发生时执行一个程序?

我不是C/C++/.NET程序员,所以如果我能够设置一些东西来触发批处理文件,那就太理想了。


可以使用VBScript和WMI完成,参见此实现http://www.go-geek.com/tips-n-tricks/monitor-directory-for-new-files-with-wsh.html - Pradeep
8个回答

25

使用类似下面的FileSystemWatcher来创建一个WatcherCreated事件。

我使用这个方法创建了一个Windows服务,用于监视一个网络文件夹,并在新文件到达时发送电子邮件给指定的组。

    // Declare a new FILESYSTEMWATCHER
    protected FileSystemWatcher watcher;
    string pathToFolder = @"YourDesired Path Here";

    // Initialize the New FILESYSTEMWATCHER
    watcher = new FileSystemWatcher {Path = pathToFolder, IncludeSubdirectories = true, Filter = "*.*"};
    watcher.EnableRaisingEvents = true;
    watcher.Created += new FileSystemEventHandler(WatcherCreated);

    void WatcherCreated(object source , FileSystemEventArgs e)
    {
      //Code goes here for when a new file is detected
    }

2
我知道你的帖子中说你不是.NET程序员,但是只要有免费的Visual Studio Express副本和我发布的代码,你就已经完成了80%的工作。Stack OverFlow可能可以帮你解决其他20%的问题。根据你想要对检测到的文件做什么,这是一个非常简单的解决方案,易于实现和部署。如果你感兴趣,我可以详细说明如何创建Window服务。 - Refracted Paladin
谢谢,我已经好几年没用C#了,但如果它是最适合这项工作的工具,那么额外的努力是值得的。我会安装Visual C# Express Edition。谢谢。 - Liam
因为PowerShell是.NET,所以不可能使用吗?你根本不需要Visual Studio。 - v.oddou
1
值得注意的是,.net自带的FileSystemWatcher并不是100%可靠的。当被监视的文件夹有很多变化时(比如一次性传入几百个文件),它可能无法及时响应。请参考https://dev59.com/OmYr5IYBdhLWcg3wJ3CU#13917670以获取详细解释。 - buddybubble
1
我认为你缺少了“Watcher.EnableRaisingEvents = true;”。另外,你在使用“watcher”和“Watcher”时不够一致。 - RenniePet
截至今天,.Net v4.6.1需要设置额外的属性:EnableRaisingEvents = true和NotifyFilter = NotifyFilters.FileName。 - Hasan Baidoun

10

FileSystemWatcher是正确的选择,但以前FileSystemWatcher只能一次处理“几个”更改。这是因为操作系统缓冲区的原因。实际上,每当复制许多小文件时,保存已更改文件名称的缓冲区就会被溢出。这种缓冲区不是跟踪最近更改的正确方式,因为操作系统必须停止写入以防止溢出。

Microsoft提供了其他设施(编辑:如更改日志),以真正捕获所有更改。本质上,这些设施是备份系统使用的,记录的事件非常复杂,并且文档化非常差。

一个简单的测试是生成大量小文件,看它们是否都由FileSystemWatcher报告。如果你有问题,我建议你绕过整个问题,在定时间隔内扫描文件系统进行更改。


6
如果您需要非程序化的内容,可以尝试使用GiPo@FileUtilities ... 不过在这种情况下,该问题就不属于这里了!

这个问题可能更适合于超级用户或者服务器故障,但是这个答案确实直接回答了提问者的问题:“是否有一种方法在发生更改时执行程序?” - Pat
GiPo@FileUtilities似乎已经被下架了,但是如果您需要非编程的东西,http://www.myassays.com/folder-poll可以提供类似的功能。 - Mister Cook

3

我在搜索文件系统活动监控的方法时找到了这个页面。我参考了Refracted Paladin的帖子以及他分享的FileSystemWatcher,并编写了一个快速而简单的C#实现:

using System;
using System.IO;

namespace Folderwatch
{
    class Program
    {
        static void Main(string[] args)
        {

            //Based on https://dev59.com/MnRA5IYBdhLWcg3w_C8w#27512511
            //and http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

            string pathToFolder = string.Empty;
            string filterPath = string.Empty;
            const string USAGE = "USAGE: Folderwatch.exe PATH FILTER \n\n e.g.:\n\n Folderwatch.exe c:\\windows *.dll";

            try
            {
                pathToFolder = args[0];

            }
            catch (Exception)
            {
                Console.WriteLine("Invalid path!");
                Console.WriteLine(USAGE);
                return;
            }

            try
            {
                filterPath = args[1];
            }
            catch (Exception)
            {
                Console.WriteLine("Invalid filter!");
                Console.WriteLine(USAGE);
                return;

            }

            FileSystemWatcher watcher = new FileSystemWatcher();

            watcher.Path = pathToFolder;
            watcher.Filter = filterPath;

            watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | 
                NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | 
                NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;

            // Add event handlers.
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.Created += new FileSystemEventHandler(OnChanged);
            watcher.Deleted += new FileSystemEventHandler(OnChanged);
            watcher.Renamed += new RenamedEventHandler(OnRenamed);


            // Begin watching.
            watcher.EnableRaisingEvents = true;

            // Wait for the user to quit the program.
            Console.WriteLine("Monitoring File System Activity on {0}.", pathToFolder);
            Console.WriteLine("Press \'q\' to quit the sample.");
            while (Console.Read() != 'q') ;

        }

        // Define the event handlers. 
        private static void OnChanged(object source, FileSystemEventArgs e)
        {
            // Specify what is done when a file is changed, created, or deleted.
            Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
        }

        private static void OnRenamed(object source, RenamedEventArgs e)
        {
            // Specify what is done when a file is renamed.
            Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
        }
    }
}

要使用这个功能,需要下载Visual Studio(Express版本就可以)。然后创建一个名为Folderwatch的新C#控制台应用程序,并将我的代码复制粘贴到Program.cs中。

作为替代方案,您可以使用Sys Internals Process Monitor:Process Monitor。它可以监视文件系统和更多内容。


3

3

我需要使用Visual Studio吗?我能在VBScript中使用它吗? - Liam
FileSystemWatcher 是 .Net 的一部分,因此这个解决方案需要使用 Visual Studio。 - Refracted Paladin

2
没有任何实用工具或程序来完成这个任务。需要一些编程。
正如另一个答案中所指出的那样,.NET的FileSystemWatcher是最简单的方法。
本地API ReadDirectoryChangesW 相对较难使用(需要了解完成端口)。

1
在浏览了几个小时的github以寻找FileSystemWatcher代码后,我发现以下页面有一些类似但不完全相同的替代方案,可以解决FileSystemWatcher的缺陷(也在一些答案中提到):

https://github.com/theXappy/FileSystemWatcherAlts

以下是针对每种情况哪种替代方案更好的比较表,底部有一个简单易懂的通用规则,解释了在哪种情况下使用哪种替代方案:

https://github.com/theXappy/FileSystemWatcherAlts/blob/master/AltComparison.md

它很容易实现或修改。如果您的项目已经使用了FileSytemWatcher,那么您只需要简单地更改这个:

FileSystemWatcher sysMonitor = new FileSystemWatcher(@"C:\");

对于以下任何一个:

IFileSystemWatcher sysMonitor = new FileSystemRefreshableWatcher(@"C:\");
IFileSystemWatcher sysMonitor = new FileSystemAutoRefreshingWatcher(@"C:\");
IFileSystemWatcher sysMonitor = new FileSystemPoller(pollingInterval: 500,path: @"C:\");
IFileSystemWatcher sysMonitor = new FileSystemOverseer(pollingInterval: 500, path: @"C:\");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接