.Net Core 抽象化了檔案系統,在.Net Core 中,很多地方都可以看見檔案系統的應用,
Ex.
app.UseStaticFiles
) ,會利用檔案系統來找尋對應的檔案既然都說了抽象,代表我們後面的是可以被替換的
在看常見的實作前,先讓我們來來檢視一下抽象的介面吧
IFileProvider.cs
public interface IFileProvider
{
IFileInfo GetFileInfo(string subpath);
IDirectoryContents GetDirectoryContents(string subpath);
IChangeToken Watch(string filter);
}
這個介面非常的單純
有取得檔案資訊(GetFileInfo
)跟資料夾資訊(IDirectoryContents
)的方法各一
還有用來通知檔案變更的方法Watch
本質上資料夾也算是一個檔案,這邊不特別去看IFileInfo
跟IDirectoryContents
我們把重點放在Watch
上
實務上,我們常常利用config檔案(web.config
、appsetting.json
等等的設定檔案),
我們可能會在Config檔案中加入功能的開關或設定。
假設線上有功能異常的時候,我們可以透過修改Config的方式及時關閉功能
而要怎麼在修改Config之後通知你的應用程式,而不用透過重啟程式的方式讓設定檔生效
靠的就是Watch 方法
ICangeToken.cs
public interface IChangeToken
{
// 檔案是否變更
bool HasChanged { get; }
// 檔案變更時是否需呼叫Callback
bool ActiveChangeCallbacks { get; }
// 註冊Callback
IDisposable RegisterChangeCallback(Action<object> callback, object state);
}
可以透過RegisterChangeCallback來取得檔案變更要觸發的事件,也可以利用靜態方法OnChanged
來註冊
範例小程式,使用PhysicalFileProvider
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
IHostBuilder builder = new HostBuilder();
var host = builder
.ConfigureServices(x =>
{
x.AddSingleton<IFileProvider>(new PhysicalFileProvider(@"C:\Sample"));
x.AddHostedService<SampleService>();
}).Build();
await host.RunAsync();
public class SampleService : IHostedService
{
private readonly IFileProvider _fileProvider;
public SampleService(IFileProvider fileProvider)
{
_fileProvider = fileProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
while (cancellationToken.IsCancellationRequested is false)
{
// 監聽所有的txt文件
_fileProvider.Watch("*.txt").RegisterChangeCallback(x =>
{
Console.WriteLine("File changed");
}, null);
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
這邊除了EmbeddedFileProvider
外會簡單介紹
實體的檔案目錄,對應電腦中實際的實體檔案
實作的部分主要是透過System.IO
去操作
這邊一樣只特別提Watch的實作
主要是透過PhysicalFilesWatcher
這個類別來實作
而在底層主要是透過FileSystemWatcher
這個物件去實作
當實體變更的時候,FileSystemWatcher
會回傳一個IChangeToken
來通知檔案變化
算是Null Object Pattern
的應用,
GetFileInfo
會回傳一個 NotFoundFileInfo
代表不存在的檔案
同樣的GetDirectoryContents
會回傳NotFoundDirectoryContents
代表找不到的資料夾Watch
一樣會回傳一個 NullChangeToken
的物件
既然沒有檔案,代表不會有變化
由一組IFileProvider
所組成
當呼叫GetFileInfo
的時候,會依序呼叫底下的IFileProvider.GetFileInfo
有找到會回傳第一個找到的
找不到會回傳一個 NotFoundFileInfo
代表不存在檔案GetDirectoryContents
跟 GetFileInfo
一樣
而Watch
方法則會監控所有滿足pattern
的變更檔案的ComposteChangeToken
CompositeFileProviderSample.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
var serviceCollection = new ServiceCollection();
var compositeFileProvider = new CompositeFileProvider(
new PhysicalFileProvider(@"C:/Sample1"),
new PhysicalFileProvider(@"C:/Sample2")
);
serviceCollection.AddSingleton<IFileProvider>(compositeFileProvider);
var serviceProvider = serviceCollection.BuildServiceProvider();
var fileProvider = serviceProvider.GetRequiredService<IFileProvider>();
Console.WriteLine("is a.txt existed :" + fileProvider.GetFileInfo("a.txt").Exists);
Console.WriteLine("is b.txt existed :" + fileProvider.GetFileInfo("b.txt").Exists);
Console.WriteLine("is c.txt existed :" + fileProvider.GetFileInfo("c.txt").Exists);
我們建了一個由分別指向Sample1跟Sample2資料夾的PhysicalFileProvider
組成的CompositeFileProvider
在Sample1跟Sample2資料夾 中分別放入兩個檔案a.txt跟b.txt
Sample1
Sample2
可以看見結果如我們所料,找到a跟b