首页 > 其他分享 >System.IO.FileSystemWatcher的坑

System.IO.FileSystemWatcher的坑

时间:2022-10-19 13:33:33浏览次数:88  
标签:文件 FileSystemWatcher Created accessable fileSystemWatcher System IO FullPath

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下运行。

为了防止无限循环,设置了超时,如果在指定的时间内无法完成,那么程序直接跳出。

参考

标签:文件,FileSystemWatcher,Created,accessable,fileSystemWatcher,System,IO,FullPath
From: https://www.cnblogs.com/podolski/p/16805923.html

相关文章

  • iOS input 以及textarea失去焦点 无法进行输入
    百度了大部分的方法都不行后续通过跟朋友一起试验/*在css中对应的input以及textarea下添加*/input,textarea{-webkit-user-select:auto!important;}iOSi......
  • CPU高利用率及IO高负载故障定位分析
    一、系统表说明MySQL5.7版本起,performance_schema.threads线程表可以查询各个线程的信息,THREAD_OS_ID值对应OS中的线程,这就为故障定位提供了便捷,SQL如下:参数:30502为OS......
  • FFmpeg中转场滤镜xfade的时间参数(duration和offset)与算法解读
    xfade转场滤镜小科普最近在研究音视频合成的相关功能,现已有两个视频剪辑。拼合成一个文件显然用concat可以完成,但是过渡生硬,而xfade滤镜可以很方便实现更加缓和的场景切换。......
  • 由于FFmpeg的amerge滤镜导致的iOS中无法载入视频
    amerge引发的问题一段视频,在合成后可能需要增加一段背景音乐来烘托气氛。然而在使用amerge进行混音时,如果不小心会出现问题。例如将合成好的视频通过AirDrop发送到iOS(因为......
  • Image Segmentation Using Text and Image Prompts论文阅读笔记
    ImageSegmentationUsingTextandImagePrompts论文阅读笔记摘要对于传统的分割方法,训练好后如果需要纳入新的类别,带来的成本是很高的。因此作者提出了一个系统,可以在......
  • vite..config.ts中Cannot find module 'path' or its corresponding type declaration
    ts中引入path模块出错Cannotfindmodule'path'oritscorrespondingtypedeclarations.解决方法第一步npminstall-D@types/node第二步在tsconfig.json中添加......
  • 我的Vue之旅 07 Axios + Golang + Sqlite3 实现简单评论机制
    第三期·使用Vue3.1+TailWind.CSS+Axios+Golang+Sqlite3实现简单评论机制效果图CommentArea.vue我们需要借助js的Data对象把毫秒时间戳转化成UTCStrin......
  • vue之axios
    什么是axios?Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中。特性1从浏览器中创建XMLHttpRequests2从node.js创建http请求3支持PromiseAPI4......
  • Unity IO 加载图片
    ///<summary>///以IO方式进行加载///</summary>privatevoidLoadByIo(stringurl,GameObjectImageOBJ){//创建文件读取流FileStream......
  • session
           不想用cookie的话Token+Redis自己实现springboot使用redis  请求每次要带上token  如果是浏览器访问。可以将token放到请求头  ......