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下運行,
為了防止無限回圈,設定了超時,如果在指定的時間內無法完成,那么程式直接跳出,
參考
- https://stackoverflow.com/questions/4277991/c-sharp-filesystemwatcher-how-to-know-file-copied-completely-into-the-watch-fol
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/518439.html
標籤:.NET Core
上一篇:訪問MATCHER中的私有成員
