緣起:
今天看到我們研發寫的一支監控檔案目錄下的檔案有沒有被更動的程式,我學到了
BackgroundService 跟 FileSystemWatcher 的使用,還有用 sc.exe
來建立服務,覺得很有趣,所以想寫個文章來學習。
我是在 windows 下操作專案的,改天有空的話會再去 linux
上面試試。
dotnet 建立 worker 專案:
我在專案資料夾打開 cmd,輸入指令來建立一個叫 TestWork
的專案
dotnet new work -o TestWork
然後用 vs code 開啟專案,需要為專案加入 Microsoft.Extensions.Hosting.WindowsServices 的套件
dotnet add package Microsoft.Extensions.Hosting.WindowsServices
worker 專案有預設的 Program.cs 跟 Work.cs 範本,我們先修改
Program
using TestWork;
var builder = Host.CreateDefaultBuilder(args);
builder.ConfigureServices((hostContext, services)=>{
services.AddHostedService<Worker>();
});
builder.UseWindowsService();
var host = builder.Build();
host.Run();
第 5 行 : 加入
Work class 的服務,它繼承 BackgroundService Class。
第 8 行 : 加入 windows service
的支援。
然後是我們的 Work.cs
namespace TestWork;
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly string _logFolderPath = Path.Combine(AppContext.BaseDirectory, "log");
private readonly string _watchFolderPath = @"C:\Users\qaz09\OneDrive\桌面\TestWatch";
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Directory.CreateDirectory(_logFolderPath);
using (var watcher = new FileSystemWatcher())
{
watcher.Path = _watchFolderPath;
watcher.IncludeSubdirectories = true;
watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.Size | NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.EnableRaisingEvents = true;
watcher.Changed += OnChange;
watcher.Created += OnChange;
watcher.Deleted += OnChange;
watcher.Renamed += OnChange;
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000, stoppingToken);
}
}
}
private void OnChange(object sender, FileSystemEventArgs args)
{
string logFilePath = Path.Combine(_logFolderPath, "log.txt");
using (StreamWriter writer = new StreamWriter(logFilePath, true))
{
writer.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd:hh:MM:ss")} | {args.ChangeType} | {args.FullPath} | {args.Name}");
}
}
}
第 6 行 : 紀錄 log 檔的位置,用
AppContext.BaseDirectory 這個泛用的方法來取得。
第 7 行 :
要監控的資料夾位置,寫死,桌面的一個 TestWatch 資料夾。
第 13 行 : HostService
跑起來會進入的 function,要回傳 Task。
第 15 行 : 沒有 log
資料夾的話建一個。
第 17 行 : 這篇的主角,FileSystemWatcher,用它監控資料夾內的變化,它有繼承
System.ComponentMode.Component,這 class 有實作 IDisposable。
第 19 行 :
指定監控的資料夾路徑。
第 20 行 : 包含子資料夾。
第 21 行 :
設定監控什麼類型的變化,用 NotifyFilters
這個 Enum 來設定。
第 22 行 :
設定檔案名稱篩選字串,預設是 "*.*"。
第 23 行 :
設定是否啟用元件。
第 25~28 行 :
設定監聽事件,當目錄下有發生檔案(或目錄)內容被更動、新增、重新命名、刪除的話,觸發我們寫的
OnChange 事件。
第 37~44 行 : OnChange
事件,它會傳進 FileSystemEventArgs
類型的參數,可以從它的成員變數取得有用的資料,像是這次的變動是什麼、檔案的完整路徑。我這邊是紀錄這些變化跟發生的時間,寫到
log.txt 裡。
用 TestWork 專案來建立服務:
接著發布專案到桌面
dotnet publish -o ..\..\TestWorkPublish
再來會用到
sc.exe,以管理者開啟 cmd,然後用 sc.exe 來建立專案的服務,我把它叫
birdshiutest
sc.exe create "birdshiutest" binpath="C:\Users\qaz09\OneDrive\桌面\TestWorkPublish\TestWork.exe"
可以在那邊看到我們建的 birdshiutest,再來就啟動它
如果想把服務砍掉的話,可以下
sc.exe delete birdshiutest
沒有留言:
張貼留言