System.IO.FileSystemWatcher的坑
System.IO命名空间下面有一个FileSystemWatcher,这个东西可以实现文件变动的提醒。需要监控文件夹变化(比如FTP服务器)的情形非常适用。
需要监控文件新建时,我们可以这么写:
_fileSystemWatcher.Path = path;
_fileSystemWatcher.IncludeSubdirectories = true;
_fileSystemWatcher.Created += _fileSystemWatcher_Created;
_fileSystemWatcher.EnableRaisingEvents = true;
protected async void _fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine(e.FullPath);
}
感觉还是挺方便的吧?接下来就是坑了。
传输延迟问题
FileSystemWatcher只要发现文件创建就触发了,大文件或者FTP等需要一段时间才能完成传输的情况下,直接在时间处理程序中处理文件会由于文件不完整导致错误。可惜的是,FileSystemWatcher并没有內建任何机制可以保障文件传输完成再触发Created事件,我们只能靠自己代码保障。
以下代码运行于.NET 6,Windows 11,Rocky Linux 9
Windows only方案
FileSystemWatcher除了Created,还提供了Changed事件,我们可以先监听Created事件,然后再监控Changed的情况,当文件属性不在变化时,认为是传输完毕了。
这种方案可行,不过感觉有点太麻烦了,我需要监听两个事件,还需要处理先后顺序,其实我只想知道创建而已...在Created事件中,使用排他性的文件打开操作
在File.Open()函数中,有重载可以提供独占的访问,访问不成功,文件会弹出错误。
//防止文件上传时间过长,导致无法正常识别
if (!File.Exists(e.FullPath)) return;
var accessable = false;
for (int i = 0; i < 5; i++)
{
try
{
using (File.Open(e.FullPath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine("Break");
accessable = true;
break;
}
}
catch (Exception)
{
Console.WriteLine("Loop" + i);
}
await Task.Delay(3000);
}
//文件超时无法读取,失败。
if (!accessable) return;
//后续代码
运行可以看见这样的输出,说明方案可行。

Linux与Windows通用方案
上面的方案似乎已经解决了我们的问题,我兴致勃勃地部署到Linux机器上时却死活无法正常工作,Debug发现Open()这个方法居然可以一次直接通过,看来Linux下的Share不能正常独占这个文件,还得换一个方法。
protected async void _fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
//防止文件上传时间过长,导致无法正常识别
if (!File.Exists(e.FullPath)) return;
var accessable = false;
for (int i = 0; i < 5; i++)
{
await Task.Delay(3000);
Console.WriteLine("loop" + i);
var time1 = File.GetLastWriteTimeUtc(e.FullPath);
await Task.Delay(1000);
var time2 = File.GetLastWriteTimeUtc(e.FullPath);
if (time1 == time2)
{
accessable = true;
break;
}
}
//文件超时无法读取,失败。
if (!accessable) return;
//后续代码
}
我们可以在程序中定时检查文件的最后修改时间,如果相隔一段时间的两次最后修改时间一致的话,那说明文件已经完成了传输,这种方式不依赖于打开操作,并且可以在Windows和Linux下运行。
为了防止无限循环,设置了超时,如果在指定的时间内无法完成,那么程序直接跳出。
参考
System.IO.FileSystemWatcher的坑的更多相关文章
- System.IO.FileSystemWatcher
这个类功能很强.可以实时监测文件系统的变化. https://msdn.microsoft.com/zh-cn/library/system.io.filesystemwatcher.aspx 事件 ...
- System.IO 二
接着上篇的来 System.IO FileSystemWatcher 指向这个签名的方法 可以监听目录发生了什么事件 例如: static void Main(string[] args) ...
- Fiddler的一些坑: !SecureClientPipeDirect failed: System.IO.IOException
手机的请求Fiddler可以捕捉,但是手机一直无法上网,在logs中看到的日志如下: !SecureClientPipeDirect failed: System.IO.IOException 由于远 ...
- C# System.IO和对文件的读写操作
System.IO命名空间中常用的非抽象类 BinaryReader 从二进制流中读取原始数据 BinaryWriter 从二进制格式中写入原始数据 BufferedStream 字节流的临时存储 ...
- System.Span, System.Memory,还有System.IO.Pipelines
System.Span, System.Memory,还有System.IO.Pipelines 使用高性能Pipelines构建.NET通讯程序 .NET Standard支持一组新的API,Sys ...
- 服务 在初始化安装时发生异常:System.IO.FileNotFoundException: "file:///D:\testService"未能加载文件或程序集。系统找不到指定文件。
@echo.@if exist "%windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" goto INSTALL ...
- C#、.Net代码精简优化(空操作符(??)、as、string.IsNullOrEmpty() 、 string.IsNullOrWhiteSpace()、string.Equals()、System.IO.Path 的用法)
一.空操作符(??)在程序中经常会遇到对字符串或是对象判断null的操作,如果为null则给空值或是一个指定的值.通常我们会这样来处理: .string name = value; if (name ...
- System.IO.Directory.Delete目录删除
在程序运行的时候,如果直接获取一个目录路径,然后执行删除(包括子目录及文件): System.IO.Directory.Delete(path,true); 或者 System.IO.Director ...
- System.IO.File.Create 不会自动释放,一定要Dispose
这样会导致W3P进程一直占用这个文件 System.IO.File.Create(HttpContext.Current.Server.MapPath(strName)) 最好加上Dispose Sy ...
随机推荐
- 小白之Python基础(四)
条件判断和循环: 1.条件判断类型: 1)if语句:(注意:if中的条件如果是:非零数值.非空字符串.非空list等,就判断为True,否则为False.) 2)if-else语句: 3)if-eli ...
- s905l3a系列刷armbian 教你从0搭建自己的博客
最近服务器又更换了,原来的有一点点小意外(一个电阻给我焊接时搞掉了). 哎~~今天,我淘到了一个好东西----CM311-3a,配置很诱人,价格也不贵,60绰绰有余 比较 CM311-3a N1(炒到 ...
- 困扰所有SAP顾问多年的问题终于解决了
相信每个从事SAP的顾问都会遇到这样的场景:听着歌,录着SAP数据,写着ABAP代码,突然一切都消失了. 是的,SAP GUI又崩溃闪退了. 可能你还一脸懵逼不知道发生什么事情,当你重新登录系统的时候 ...
- LuoguP2575 高手过招(博弈论)
空格数变吗?不变呀 阶梯博弈阶梯数变吗?不变呀 那这不就阶梯博弈,每行一栋楼,爬完\(mex\)就可以了吗? #include <iostream> #include <cstdio ...
- 前端React项目遇到【Uncaught SyntaxError: Unexpected token '<'】错误的解决方式
问题描述 前端部署好项目后,打开相应的页面显示一片空白,打开console显示 问题排查思路 理解问题的本质 出现这个错误的原因是浏览器期望得到js文件,但页面却返回了html文件,如图中的js文件点 ...
- 基础3:js实现继承的多种方式
js实现继承的多种方式 1. 原型链继承 function Parent() { this.name = 'xwk' } Parent.prototype.getName = function() { ...
- 3-14 Python处理XML文件
xml文件处理 什么是xml文件? xml即可扩展标记语言,它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言. 从结构上,很像HTML超文本标记语言.但他们被设计的目的 ...
- KingbaseES V8R6备份恢复案例之---同一数据库创建不同stanza备份
案例说明: 在生产环境,有的应用需要调用数据库的sys_rman做备份,为了区分数据库自身的sys_rman备份和应用的备份,可以使用不同的stanza name创建备份.本案例介绍了,如何在King ...
- Nginx超时问题解决
在 nginx.conf 中配置以下内容 ... http { ... server { # 这里表示upstream 的连接.读取.发送超时时间都是300秒 proxy_connect_timeou ...
- Eclipse配置Tomcat搭建java Web (JSP)开发环境
配置Tomcat服务 1.打开窗口-首选项-Server-Runtiome Environments 2.点击ADD,选择对应的Tomcat版本,点击下一步 路径选择Tomcat解压后的文件夹目录,点 ...