使用C#如何监控选定文件夹中文件的变动情况?
目录
1、前言
2、效果
3、具体实现
页面设计
全部代码
FileSystemWatcher的介绍
FileSystemWatcher的构造函数
FileSystemWatcher的属性
FileSystemWatcher的事件
4、总结
前言
有时候我们会有监控电脑上某一个文件夹中文件变动情况的需求,在本文中,我也会以一个具体的例子,说明在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事件的代码如下所示:
/// <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;
}
}
可知将值赋给了_onChangedHandler,我们再来查看_onChangedHandler的定义:
// Event handlers
private FileSystemEventHandler? _onChangedHandler;
类型为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#中的FileSystemWatcher类实现监控选定的文件夹,希望对你有所帮助。
使用C#如何监控选定文件夹中文件的变动情况?的更多相关文章
- C# 将文件夹中文件复制到另一个文件夹
p{ text-align:center; } blockquote > p > span{ text-align:center; font-size: 18px; color: #ff0 ...
- python批量处理文件夹中文件的问题
用os模块读取文件夹中文件 原来的代码: import osfrom scipy.misc import imread filenames=os.listdir(r'./unprocess')for ...
- php获取指定文件夹中文件名称
/** * php获取指定文件夹中文件名称 * @author jackie <2018.10.10> */ public static function getFileName($fil ...
- Python按顺序读取文件夹中文件
参考资料: https://blog.csdn.net/qq_22227123/article/details/79903116 https://blog.csdn.net/merdy_xi/arti ...
- C#实现对指定文件夹中文件按修改时间排序
string path = "~/Document/Introduction/团队管理制度/"; DirectoryInfo dirinfo = new Di ...
- 【linux】复制文件夹中文件,排除部分文件
如下 cp `ls|grep -v -E '*json|out'|xargs` /home/data/ 用grep -v 表示排除, -E 表示正则 ls|grep -v -E '*json|out ...
- Java访问文件夹中文件的递归遍历代码Demo
上代码: import java.io.File; /* * 需求:对指定目录进行所有内容的列出(包含子目录中的内容) * 也可以理解为 深度遍历. */ public class FindAllFi ...
- Python之获取文件夹中文件列表以及glob与fnmatch模块的使用
获取文件夹中的文件列表 print(os.listdir("../secondPackage")) # ['__init__.py', 'secondCookBook.py', ' ...
- 使用java读取文件夹中文件的行数
使用java统计某文件夹下所有文件的行数 经理突然交代一个任务:要求统计某个文件夹下所有文件的行数.在网上查了一个多小时没有解决.后来心里不爽就决定自己写一个java类用来统计文件的行数,于是花了两个 ...
- 使用.NET统计文件夹中文件总数
软件下载: http://hovertree.com/h/bjaf/hwqtjwjs.htm 截图: 使用方法:点击按钮,选择文件夹,就可以显示文件夹中包含的文件总数. 这个项目包含在HoverTre ...
随机推荐
- ubuntu22.04.3 安装postgresql 16 rc1数据库
ubuntu22.04.3 安装postgresql 16 rc1数据库 一.直接安装 # Create the file repository configuration: sudo sh -c ' ...
- Spring-Boot-Starter 学习笔记(1)
Spring-Boot-Starter 1. 准备配置类和 Bean 对象 Spring Boot 提供了两个注解: @Configuration:Spring 提供的配置类注解,作用在类上,代表整个 ...
- 6. 用Rust手把手编写一个wmproxy(代理,内网穿透等), 通讯协议源码解读篇
用Rust手把手编写一个wmproxy(代理,内网穿透等), 通讯协议源码解读篇 项目 ++wmproxy++ gite: https://gitee.com/tickbh/wmproxy githu ...
- Destoon模板存放及调用规则
一.模板存放及调用规则 模板存放于系统 template 目录,template 目录下的一个目录例如 template/default/ 即为一套模板模板文件以 .htm 为扩展名,可直接存放于模板 ...
- MySQL系列之——MySQL介绍和安装、MySQL简介及产品线、安装方式(源码安装 rpm方式 yum方式 通用二进制安装)
文章目录 一 MySQL介绍和安装 1.1 什么是数据? 1.2 什么是数据库管理系统(DBMS)? 1.3 数据库管理系统种类 二 MySQL简介及产品线 2.1 MySQL行业主流版本 2.2 企 ...
- tiptop查询通配符
*:表示任何符合的字符,例:A*,表示要找出全部为 A 开头的资料. ?:表示任一符合的字符,例:A?,表示要找出第一码为 A,第二码为任何 字符,但总共只有二码之数据. 注:以上二功能仅可在文字字段 ...
- 产品代码都给你看了,可别再说不会DDD(七):实体与值对象
这是一个讲解DDD落地的文章系列,作者是<实现领域驱动设计>的译者滕云.本文章系列以一个真实的并已成功上线的软件项目--码如云(https://www.mryqr.com)为例,系统性地讲 ...
- 手撕Vue-界面驱动数据更新
经过上一篇文章,已经将数据驱动界面改变的过程实现了,本章节将实现界面驱动数据更新的过程. 界面驱动数据更新的过程,主要是通过 v-model 指令实现的, 只有 v-model 指令才能实现界面驱动数 ...
- 搓一个Pythonic list
总所周知,Python语言当中的list是可以存储不同类型的元素的,对应到现代C++当中,可以用std::variant或者std::any实现类似的功能.而Python官方的实现当中用到了二级指 ...
- DNS 服务 docker-bind 的部署使用
前言 前面使用 nginx 代理转发了几个域名到服务器,但是每次添加一个域名都需要在客户端添加一行 hosts 文件,无疑是繁琐的,其中也提到可以使用 DNS 来实现自动解析域名 到指定服务器的功能, ...