详解C#如何监控选定文件夹中文件的变动情况
作者:Dm_dotnet
前言
有时候我们会有监控电脑上某一个文件夹中文件变动情况的需求,在本文中,我也会以一个具体的例子,说明在C#中如何使用FileSystemWatcher类来实现上述需求。
效果
具体实现
如果你对C#如何监控选定文件夹中文件的变动情况感兴趣,可以继续往下阅读。
界面设计
为了更好的演示效果,我这里winform的界面设计如下:
很简单,只有一个button与一个richtextbox,button用来指定被监控的文件,richtextbox用来输出一些信息。
全部代码
namespace FileSystemWatcherDemo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // 创建一个 FolderBrowserDialog 实例 FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog(); // 设置对话框的标题 folderBrowserDialog.Description = "选择文件夹"; // 如果用户点击了“确定”按钮 if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { richTextBox1.Text = ""; // 获取用户选择的文件夹路径 string selectedFolder = folderBrowserDialog.SelectedPath; // 提示被监控文件夹路径 richTextBox1.Text += $"被监控的文件夹为:{selectedFolder}\r\n"; var watcher = new FileSystemWatcher($"{selectedFolder}"); watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size; watcher.Changed += OnChanged; watcher.Created += OnCreated; watcher.Deleted += OnDeleted; watcher.Renamed += OnRenamed; watcher.Filter = "*.txt"; watcher.IncludeSubdirectories = true; watcher.EnableRaisingEvents = true; } else { MessageBox.Show("您本次没有选择文件夹!!!"); } } private void AppendMessageToRichTextBox(string message) { // 在RichTextBox中添加提示信息 richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(message + Environment.NewLine); })); } private void OnChanged(object sender, FileSystemEventArgs e) { if (e.ChangeType != WatcherChangeTypes.Changed) { return; } AppendMessageToRichTextBox($"Changed: {e.FullPath}"); } private void OnCreated(object sender, FileSystemEventArgs e) { string value = $"Created: {e.FullPath}"; AppendMessageToRichTextBox($"Created: {e.FullPath}"); } private void OnDeleted(object sender, FileSystemEventArgs e) { AppendMessageToRichTextBox($"Deleted: {e.FullPath}"); } private void OnRenamed(object sender, RenamedEventArgs e) { AppendMessageToRichTextBox($"Renamed:"); AppendMessageToRichTextBox($" Old: {e.OldFullPath}"); AppendMessageToRichTextBox($" New: {e.FullPath} "); } } }
FileSystemWatcher的介绍
看过以上代码,会发现核心就是FileSystemWatcher的使用。接下来我将介绍一下C#中的FileSystemWatcher类。
FileSystemWatcher是C#中的一个类,该类可以侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。
FileSystemWatcher的构造函数
该类有三种构造函数,如下所示:
形式 | 含义 |
---|---|
FileSystemWatcher() | 初始化 FileSystemWatcher 类的新实例。 |
FileSystemWatcher(String) | 初始化 FileSystemWatcher 类的新实例,给定要监视的目录。 |
FileSystemWatcher(String, String) | 初始化 FileSystemWatcher类的新实例,给定要监视的目录和文件类型。 |
var watcher = new FileSystemWatcher($"{selectedFolder}");
本文中我选择的就是第二种构造函数,指定要监视的目录。
FileSystemWatcher的属性
现在介绍一下在本示例中用到的FileSystemWatcher的属性,如下所示:
名称 | 类型 | 含义 |
---|---|---|
EnableRaisingEvents | bool | 设置FileSystemWatcher是否有效 |
Filter | string | 设置一个要监控的文件的格式 |
Filters | Collection | 设置多个要监控的文件的格式 |
IncludeSubdirectories | bool | 获取或设置一个值,该值指示是否应监视指定路径中的子目录 |
NotifyFilter | NotifyFilters | 获取或设置要监视的更改的类型 |
Path | string | 获取或设置要监视的目录的路径 |
现在来解释下所用到的代码的含义:
watcher.Filter = "*.txt";
表示要监控的文件为.txt格式。
watcher.IncludeSubdirectories = true;
表示指定路径中的子目录也要监视。
watcher.EnableRaisingEvents = true;
表示该对象可以触发事件,也就是还有效。
watcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
设置要监视的更改的类型。NotifyFilter属性的类型为NotifyFilters枚举类型。
NotifyFilters枚举类型:
[System.Flags] public enum NotifyFilters
指定要在文件或文件夹中监视的更改。
此枚举支持其成员值的按位组合。
该枚举类型包含的值与含义如下所示:
名称 | 含义 |
---|---|
Attributes | 文件或文件夹的属性 |
CreationTime | 文件或文件夹的创建时间 |
DirectoryName | 目录名 |
FileName | 文件的名称 |
LastAccess | 文件或文件夹上一次打开的日期 |
LastWrite | 上一次向文件或文件夹写入内容的日期 |
Security | 文件或文件夹的安全设置 |
Size | 文件或文件夹的大小 |
在这里使用了该枚举类型的按位组合表示这几种更改的类型要受到监视。
FileSystemWatcher的事件
FileSystemWatcher中的事件如下:
名称 | 含义 |
---|---|
Changed | 当更改指定 Path 中的文件和目录时发生 |
Created | 当在指定Path 中创建文件和目录时发生 |
Deleted | 删除指定Path中的文件或目录时发生 |
Renamed | 重命名指定 Path中的文件或目录时发生 |
Error | 当 FileSystemWatcher 的实例无法继续监视更改或内部缓冲区溢出时发生 |
watcher.Changed += OnChanged; watcher.Created += OnCreated; watcher.Deleted += OnDeleted; watcher.Renamed += OnRenamed;
在这里我使用到了Changed、Created、Deleted和Renamed事件。
我将以Changed 事件为例,详细解释一下:
watcher.Changed += OnChanged;
这行代码的含义。
我们查看FileSystemWatcher的源代码,Changed事件的代码如下所示
可知将值赋给了_onChangedHandler
,我们再来查看_onChangedHandler
的定义:
/// <devdoc> /// Occurs when a file or directory in the specified <see cref='System.IO.FileSystemWatcher.Path'/> is changed. /// </devdoc> public event FileSystemEventHandler? Changed { add { _onChangedHandler += value; } remove { _onChangedHandler -= value; } }
类型为FileSystemEventHandler?与Changed事件一致,再来看看FileSystemEventHandler?的定义:
public delegate void FileSystemEventHandler(object sender, FileSystemEventArgs e);
发现是一个参数类型分别为object、FileSystemEventArgs返回值类型为空的委托类型。
object我们知道,那么FileSystemEventArgs又是什么呢?
查看它的源码,截取一部分,如下所示:
public class FileSystemEventArgs : EventArgs { private readonly WatcherChangeTypes _changeType; private readonly string? _name; private readonly string _fullPath; /// <devdoc> /// Gets one of the <see cref='System.IO.WatcherChangeTypes'/> values. /// </devdoc> public WatcherChangeTypes ChangeType { get { return _changeType; } } /// <devdoc> /// Gets the fully qualified path of the affected file or directory. /// </devdoc> public string FullPath { get { return _fullPath; } } /// <devdoc> /// Gets the name of the affected file or directory. /// </devdoc> public string? Name { get { return _name; } } }
发现FileSystemEventArgs继承自EventArgs,而EventArgs表示包含事件数据的类的基类,因此可以明白FileSystemEventArgs表示为目录事件:Changed, Created, Deleted提供数据的类。
FileSystemEventArgs提供三个数据分别为ChangeType、FullPath、Name。
那ChangeType是什么呢?
查看ChangeType的定义:
// // 摘要: // Changes that might occur to a file or directory. [Flags] public enum WatcherChangeTypes { // // 摘要: // The creation of a file or folder. Created = 1, // // 摘要: // The deletion of a file or folder. Deleted = 2, // // 摘要: // The change of a file or folder. The types of changes include: changes to size, // attributes, security settings, last write, and last access time. Changed = 4, // // 摘要: // The renaming of a file or folder. Renamed = 8, // // 摘要: // The creation, deletion, change, or renaming of a file or folder. All = 15 }
是一个枚举类型,表示更改的类型。
现在回过头来看:
watcher.Changed += OnChanged;
OnChanged方法如下:
private void OnChanged(object sender, FileSystemEventArgs e) { if (e.ChangeType != WatcherChangeTypes.Changed) { return; } AppendMessageToRichTextBox($"Changed: {e.FullPath}"); }
为什么可以将OnChanged方法订阅到watcher.Changed事件上呢?
因为OnChanged方法与watcher.Changed事件中的委托类型FileSystemEventHandler的返回类型和签名是相同的。
OnChanged方法的返回类型与签名如下:
private void OnChanged(object sender, FileSystemEventArgs e)
FileSystemEventHandler委托类型的定义如下:
public delegate void FileSystemEventHandler(object sender, FileSystemEventArgs e);
现在已经理解了订阅事件,那么什么时候触发事件呢?
查看FileSystemWatcher的部分源码:
/// <devdoc> /// Raises the <see cref='System.IO.FileSystemWatcher.Changed'/> event. /// </devdoc> protected void OnChanged(FileSystemEventArgs e) { InvokeOn(e, _onChangedHandler); } private void InvokeOn(FileSystemEventArgs e, FileSystemEventHandler? handler) { if (handler != null) { ISynchronizeInvoke? syncObj = SynchronizingObject; if (syncObj != null && syncObj.InvokeRequired) syncObj.BeginInvoke(handler, new object[] { this, e }); else handler(this, e); } }
当发生相应的改变时,就会调用FileSystemWatcher类的OnChanged方法,从而触发事件。
以上就是详解C#如何监控选定文件夹中文件的变动情况的详细内容,更多关于C#监控文件的资料请关注脚本之家其它相关文章!