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的坑的更多相关文章

  1. System.IO.FileSystemWatcher

    这个类功能很强.可以实时监测文件系统的变化. https://msdn.microsoft.com/zh-cn/library/system.io.filesystemwatcher.aspx 事件 ...

  2. System.IO 二

    接着上篇的来  System.IO FileSystemWatcher    指向这个签名的方法   可以监听目录发生了什么事件 例如: static void Main(string[] args) ...

  3. Fiddler的一些坑: !SecureClientPipeDirect failed: System.IO.IOException

    手机的请求Fiddler可以捕捉,但是手机一直无法上网,在logs中看到的日志如下: !SecureClientPipeDirect failed: System.IO.IOException 由于远 ...

  4. C# System.IO和对文件的读写操作

      System.IO命名空间中常用的非抽象类 BinaryReader 从二进制流中读取原始数据 BinaryWriter 从二进制格式中写入原始数据 BufferedStream 字节流的临时存储 ...

  5. System.Span, System.Memory,还有System.IO.Pipelines

    System.Span, System.Memory,还有System.IO.Pipelines 使用高性能Pipelines构建.NET通讯程序 .NET Standard支持一组新的API,Sys ...

  6. 服务 在初始化安装时发生异常:System.IO.FileNotFoundException: "file:///D:\testService"未能加载文件或程序集。系统找不到指定文件。

    @echo.@if exist "%windir%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe" goto INSTALL ...

  7. C#、.Net代码精简优化(空操作符(??)、as、string.IsNullOrEmpty() 、 string.IsNullOrWhiteSpace()、string.Equals()、System.IO.Path 的用法)

    一.空操作符(??)在程序中经常会遇到对字符串或是对象判断null的操作,如果为null则给空值或是一个指定的值.通常我们会这样来处理: .string name = value; if (name ...

  8. System.IO.Directory.Delete目录删除

    在程序运行的时候,如果直接获取一个目录路径,然后执行删除(包括子目录及文件): System.IO.Directory.Delete(path,true); 或者 System.IO.Director ...

  9. System.IO.File.Create 不会自动释放,一定要Dispose

    这样会导致W3P进程一直占用这个文件 System.IO.File.Create(HttpContext.Current.Server.MapPath(strName)) 最好加上Dispose Sy ...

随机推荐

  1. Blazor和Vue对比学习(进阶2.2.3):状态管理之状态共享,Blazor的依赖注入和第三方库Fluxor

    Blazor没有提供状态共享的方案,虽然依赖注入可以实现一个全局对象,这个对象可以拥有状态.计算属性.方法等特征,但并不具备响应式.比如,组件A和组件B,都注入了这个全局对象,并引用了全局对象上的数据 ...

  2. 后端统一处理返回前端日期LocalDateTime格式化去T,Long返回前端损失精度问题

    一.前言 我们在实际开发中肯定会遇到后端的时间传到前端是这个样子的:2022-08-02T15:43:50 这个时候前后端就开始踢皮球了,!! 后端说:前端来做就可! 前端说:后端来做就可! 作为一名 ...

  3. 【喜讯】Apache DolphinScheduler 荣获 “2020 年度十大开源新锐项目”

    经 10000+ 开发者公开票选,20+专家评审. 10+ 主编团打分,历经数月打磨,11 月 19 日,由InfoQ 发起并组织的[2020中国技术力量年度榜单评选]结果正式揭晓. 2020 年度十 ...

  4. 关于linux的一点好奇心(四):tail -f文件跟踪实现

    关于文件跟踪,我们有很多的实际场景,比如查看某个系统日志的输出,当有变化时立即体现,以便进行问题排查:比如查看文件结尾的内容是啥,总之是刚需了. 1. 自己实现的文件跟踪 我们平时做功能开发时,也会遇 ...

  5. 面试突击74:properties和yml有什么区别?

    properties 和 yml 都是 Spring Boot 支持的两种配置文件,它们可以看作是 Spring Boot 在不同时期的两款"产品".在 Spring Boot 时 ...

  6. 【Django】DRF开发中的一些技巧记录

    问题记录 问题1:信号没有按预期触发 描述 编写了信号函数后,并没有如预期一般在必要时候触发,函数如下: @receiver(signals.post_save, sender=Prometheus) ...

  7. Linux下自动删除过期备份和自动异地备份

    每天自动删除过期备份 首先编写一个简单的Shell脚本DeleteExpireBackup.sh: #!/bin/bash # 修改需要删除的路径 location="/database/b ...

  8. OpenFOAM 编程 | One-Dimensional Transient Heat Conduction

    0. 写在前面 本文中将对一维瞬态热传导问题进行数值求解,并基于OpenFOAM类库编写求解器.该问题参考自教科书\(^{[1]}\)示例 8.1. 1. 问题描述 一维瞬态热传导问题控制方程如下 \ ...

  9. 手把手教你用Java获取IP归属地

    前几个月微信公众号上线了IP归属地的功能,后续知乎.抖音等平台纷纷添加了该功能.如果是国内的用户精确到省份,国外用户精确到国家.本文就使用Java实现获取IP归属地. ! 主要讲解几个步骤: Java ...

  10. Windows LDAP加固之LDAP over SSL和通道绑定

    很多网络通信都可以用SSL来加密的,LDAP也不列外,同样可以用SSL加密. LDAPS使用的证书必须满足以下几个条件: 1.证书的增强性密钥用法中必须有服务器身份验证Server Authentic ...