iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0
Modern Web

擁抱 .Net Core系列 第 8

[Day8] 檔案提供者(檔案系統)

  • 分享至 

  • xImage
  •  

.Net Core 抽象化了檔案系統,在.Net Core 中,很多地方都可以看見檔案系統的應用,
Ex.

  • 靜態檔案(app.UseStaticFiles) ,會利用檔案系統來找尋對應的檔案
  • Razor Page 也會使用他來提供View
  • Web的跟目錄也是靠他去定位的

既然都說了抽象,代表我們後面的是可以被替換的
在看常見的實作前,先讓我們來來檢視一下抽象的介面吧

IFileProvider

IFileProvider.cs

public interface IFileProvider
{
    IFileInfo GetFileInfo(string subpath);

    IDirectoryContents GetDirectoryContents(string subpath);

    IChangeToken Watch(string filter);
}

這個介面非常的單純
有取得檔案資訊(GetFileInfo)跟資料夾資訊(IDirectoryContents)的方法各一
還有用來通知檔案變更的方法Watch

本質上資料夾也算是一個檔案,這邊不特別去看IFileInfoIDirectoryContents
我們把重點放在Watch

監聽檔案變化

實務上,我們常常利用config檔案(web.configappsetting.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();
    }
}

常見的IFileProvider實作

  • PhysicalFileProvider
  • EmbeddedFileProvider
  • NullFileProvider
  • CompositeFileProvider

這邊除了EmbeddedFileProvider 外會簡單介紹

PhysicalFileProvider

實體的檔案目錄,對應電腦中實際的實體檔案
實作的部分主要是透過System.IO 去操作
這邊一樣只特別提Watch的實作

主要是透過PhysicalFilesWatcher 這個類別來實作
而在底層主要是透過FileSystemWatcher這個物件去實作
當實體變更的時候,FileSystemWatcher 會回傳一個IChangeToken來通知檔案變化

NullFileProvider

算是Null Object Pattern的應用,

GetFileInfo 會回傳一個 NotFoundFileInfo 代表不存在的檔案
同樣的
GetDirectoryContents 會回傳NotFoundDirectoryContents 代表找不到的資料夾
Watch 一樣會回傳一個 NullChangeToken的物件
既然沒有檔案,代表不會有變化

CompositeFileProvider

由一組IFileProvider 所組成
當呼叫GetFileInfo 的時候,會依序呼叫底下的IFileProvider.GetFileInfo 有找到會回傳第一個找到的
找不到會回傳一個 NotFoundFileInfo 代表不存在檔案
GetDirectoryContentsGetFileInfo 一樣

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
https://ithelp.ithome.com.tw/upload/images/20220919/20109549zGjthkEhkt.png

Sample2
https://ithelp.ithome.com.tw/upload/images/20220919/20109549VG580MBFYp.png

可以看見結果如我們所料,找到a跟b
https://ithelp.ithome.com.tw/upload/images/20220919/201095490fq5rZfZAt.png


上一篇
[Day7] asp.net core 中的Web主機(Host) - 2
下一篇
[Day9] 補坑之談談 .Net core 的相依性注入實作
系列文
擁抱 .Net Core30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言