1. 程式人生 > >.NET Core的檔案系統[1]:讀取並監控檔案的變化

.NET Core的檔案系統[1]:讀取並監控檔案的變化

ASP.NET Core 具有很多針對檔案讀取的應用。比如我們傾向於採用JSON檔案來定義配置,所以應用就會涉及針對配置檔案讀取。如果使用者傳送一個針對物理檔案的HTTP請求,應用會根據指定的路徑讀取目標檔案的內容並對請求予以響應。在一個ASP.NET Core MVC應用中,針對View的動態編譯會涉及到根據預定義的路徑對映關係來讀取目標View。這些不同應用場景都會出現一個FileProvider物件的身影,以此物件為核心的檔案系統提供了統一的API來讀取檔案的內容並監控內容的改變。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中]

目錄
一、一個抽象的“檔案系統”
二、呈現檔案系統的結構
三、讀取物理檔案內容
四、讀取內嵌於程式集中的檔案內容
五、監控檔案的變化

一、一個抽象的“檔案系統”

本章所謂的“檔案系統”有點名不副實,其實根本算不上一個系統,它僅僅是利用一個抽象化的FileProvider以統一的方式提供所需的檔案而已。不過筆者實在想不到一個更為貼切的描述短語,所以還是姑且稱之為檔案系統吧(github上對應的專案名稱就叫FileSystem)。作為檔案系統的核心,FileProvider是對所有實現了IFileProvider介面的所有型別以及對應物件的統稱。正式因為FileProvider自身是個抽象的物件,所以由它構建的也是一個抽象的檔案系統。

這個檔案系統採用目錄的方式來組織和規劃檔案,但是這裡所謂的目錄和檔案都是一個抽象的概念,並非對一個具體物理目錄和檔案的對映。檔案系統的目錄僅僅是檔案的邏輯容器,而檔案可能對應一個物理檔案,也可能儲存在資料庫中,或者來源於網路,甚至有可能根本就不能存在,其內容需要在讀取時動態生成。為了讓讀者朋友們能夠對這個檔案系統具有一個大體認識,我們先來演示幾個簡單的例項。

二、呈現檔案系統的結構

檔案系統中的檔案以目錄的形式進行組織,一個FileProvider可以視為針對一個根目錄的對映。目錄除了可以存放檔案之外,還可以包含多個子目錄,所以目錄/檔案在整體上呈現出樹形層細化結構。接下來我們利用提供的FileProvider物件並將它對映到一個物理目錄,最終將所在目錄的整個結構呈現出來。

我們建立一個控制檯應用,並新增相應的NuGet包。由於IFileProvider介面定義在“Microsoft.Extensions.FileProviders.Abstractions”這個NuGet包中,針對物理檔案的FileProvider(PhysicalFileProvider)所在的NuGet包名為“Microsoft.Extensions.FileProviders.Physical

”,所以我們只需要新增後者的依賴即可。除此之外,我們將採用針對依賴注入的程式設計方式,我們還添加了針對“Microsoft.Extensions.DependencyInjection”這個NuGet包的依賴。如下所示的是針對這兩個NuGet包的依賴在project.json檔案中的定義。

   1: {  
   2:   ...
   3:   "dependencies": {
   4:     ...
   5:     "Microsoft.Extensions.DependencyInjection"    : "1.0.0",
   6:     "Microsoft.Extensions.FileProviders.Physical"    : "1.0.0"
   7:   },
   8:   ...
   9: }

我們定義瞭如下一個IFileManager介面,它利用一個唯一的方式ShowStructure將檔案系統的整體結構顯示出來。該方法具有一個型別為Action<int, string>的引數,後者負責將檔案系統的節點(目錄或者檔案)呈現出來。對於這個Action<int, string>委託物件的兩個泛型引數,第一個整型引數代表縮排的層級,後一個代表需要顯示的目錄或者檔案的名稱。

   1: public interface IFileManager
   2: {
   3:     void ShowStructure(Action<int, string> render);
   4: }

如下所示的是實現了上面這個IFileManager介面的FileManager型別。構建檔案系統的FileProvider物件對應著同名的只讀屬性,該屬性在建構函式中通過對應的引數進行賦值。目標檔案系統的整體結構最終是通過Render方法以遞迴的方式呈現出來的,這其中涉及到FileProvider的GetDirectoryContents方法的呼叫。該方法返回一個DirectoryContents物件表示由指定路徑指向的目錄內容,如果對應的目錄存在,我們可以遍歷該物件得到它的子目錄和檔案。目錄和檔案通過一個FileInfo物件來表示,至於究竟是目錄還是檔案,則通過其屬性IsDirectory來區分。

   1: public class FileManager: IFileManager
   2: {
   3:     public IFileProvider FileProvider { get; private set; }
   4:  
   5:     public FileManager(IFileProvider fileProvider)
   6:     {
   7:         this.FileProvider = fileProvider;
   8:     }
   9:  
  10:     public void ShowStructure (Action<int, string> render)
  11:     {
  12:         int layer = -1;
  13:         Render("", ref layer, render);
  14:     }
  15:  
  16:     private void Render(string subPath, ref int layer, Action<int, string> render)
  17:     {
  18:         layer++;
  19:         foreach (var fileInfo in this.FileProvider.GetDirectoryContents(subPath))
  20:         {
  21:             render(layer, fileInfo.Name);
  22:             if (fileInfo.IsDirectory)
  23:             {
  24:                 Render($@"{subPath}\{fileInfo.Name}".TrimStart('\\'), ref layer, render);
  25:             }
  26:         }
  27:         layer--;
  28:     }
  29: }

接下來我們為演示的FileProvider構建一個對映的物理目錄。將“C:\Test\”目錄作為根目錄,然後按照如下圖所示的結構在它下面建立相應的子目錄和檔案。我們將利用對映為該目錄的FileProvider建立上面定義的這個FileManager,那麼呼叫它的ShowStructure方法應該呈現出與物理目錄完全一致的結構。

1

我們在Main方法中編寫了如下的演示程式。我們針對目錄“C:\Test\”建立了一個PhysicalFileProvider物件,並採用服務介面型別IFileProvider註冊到ServiceCollection物件上。除此之外,註冊到同一個ServiceCollection物件上的還有IFileViwer和FileManager之間的對映。

   1: new ServiceCollection()
   2:     .AddSingleton<IFileProvider>(new PhysicalFileProvider(@"c:\test"))
   3:     .AddSingleton<IFileManager, FileManager>()
   4:     .BuildServiceProvider()
   5:     .GetService<IFileManager>()
   6:     .ShowStructure((layer, name) => Console.WriteLine("{0}{1}", new string('\t', layer), name));

我們最終利用ServiceCollection生成的ServiceProvider得到FileManager物件,並呼叫其ShowStructure方法將PhysicalFileProvider物件對映的目錄結構呈現出來。當我們執行該程式之後,控制檯上將呈現出如下所示的輸出結果,該結果為我們展示了對映物理目錄的真實結構。

image

三、讀取物理檔案內容

上面我們演示瞭如何利用FileProvider將檔案系統的結構完整地呈現出來,接下來我們來演示如何利用它來讀取一個具體檔案的內容。我們為IFileManager定義如下一個ReadAllTextAsync方法以非同步的方式讀取指定路徑對應的檔案,並以字串的形式返回讀取的內容。FileManager依然利用一個FileProvider來完成針對檔案的讀取工作。具體來說,它將指定的檔案路徑作為引數呼叫其GetFileInfo方法並得到一個FileInfo物件。接下來,我們呼叫FileInfo的CreateReadStream得到讀取檔案的輸出流,並利用後者得到檔案的真實內容,最終採用最簡單的ASCII碼轉換成返回的字串。

   1: public interface IFileManager
   2: {
   3:     ...
   4:     Task<string> ReadAllTextAsync(string path);
   5: }
   6:  
   7: public class FileManager : IFileManager
   8: {
   9:     ...
  10:     public async Task<string> ReadAllTextAsync(string path)
  11:     {
  12:         byte[] buffer;
  13:         using (Stream readStream = this.FileProvider.GetFileInfo(path).CreateReadStream())
  14:         {
  15:             buffer = new byte[readStream.Length];
  16:             await readStream.ReadAsync(buffer, 0, buffer.Length);
  17:         }
  18:         return Encoding.ASCII.GetString(buffer);
  19:     }
  20: }

假設我們依然將FileManager使用的FileProvider對映為目錄“C:\Test\”,現在我們該目錄中建立一個名為data.txt的文字檔案,並在該檔案中任意寫入一些內容。接下來我們在Main方法中編寫了如下的程式利用依賴注入的方式得到FileManager物件,並讀取檔案data.txt的內容。最終的除錯斷言旨在確定通過FileProvider讀取的確實就是目標檔案的真實內容。

   1: string content = new ServiceCollection()
   2:     .AddSingleton<IFileProvider>(new PhysicalFileProvider(@"c:\test"))
   3:     .AddSingleton<IFileManager, FileManager>()
   4:     .BuildServiceProvider()
   5:     .GetService<IFileManager>()
   6:     .ReadAllTextAsync("data.txt").Result;
   7:  
   8: Debug.Assert(content == File.ReadAllText(@"c:\test\data.txt"));

四、讀取內嵌於程式集中的檔案內容

我們一直在強調由FileProvider構建的是一個抽象的具有目錄結構的檔案系統,具體檔案的提供方式取決於具體FileProvider的實現。由於我們定義的FileManager並沒有限定具體使用何種型別的FileProvider,後者是在應用中通過依賴注入的方式指定的。由於上面的應用程式注入的是一個PhysicalFileProvider物件,所以我們可以利用它來讀取對應目錄下的某個檔案。假設現在我們將這個hello.txt直接以資原始檔的形式編譯到程式集中,我們就需要使用另一個名為EmbeddedFileProvider的FileProvider

現在我們直接將這個data.txt檔案新增到控制檯應用的專案根目錄下。在預設的情況下,當我們編譯專案的時候這樣的檔案並不能成為內嵌到目標程式集的資原始檔,為此我們需要在project.json上作一些與編譯相關的設定。具體來說,我們需要按照如下的方式將檔案hello.txt的路徑新增到通過配置節“buildOptions/embed”表示的內嵌檔案列表中。除此之外,由於EmbeddedFileProvider定義在“Microsoft.Extensions.FileProviders.Embedded”這個NuGet包中,我們需要新增針對它的依賴。

   1: {
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed": ["data.txt"]
   6:   },
   7:   "dependencies": {
   8:     ...
   9:     "Microsoft.Extensions.DependencyInjection"       : "1.0.0",
  10:     "Microsoft.Extensions.FileProviders.Embedded"    : "1.0.0"
  11:   },
  12:   ...
  13: }

我們編寫了如下的程式來演示針對內嵌於程式集中的資原始檔的讀取。我們首先得到當前入口程式集,並利用它建立了一個EmbeddedFileProvider,後者替換原來的PhysicalFileProvider物件被註冊到ServiceCollection之上。我們接下來採用與上面完全一致的程式設計方式得到FileManager物件並利用它讀取內嵌檔案data.txt的內容。為了驗證讀取的目標檔案準確無誤,我們採用直接讀取資原始檔的方式得到了內嵌檔案data.txt的內容,並利用一個除錯斷言確定兩者的一致性。

   1: Assembly assembly = Assembly.GetEntryAssembly();
   2:  
   3: //利用EmbeddedFileProvider讀取檔案
   4: string content1 = new ServiceCollection()
   5:     .AddSingleton<IFileProvider>(new EmbeddedFileProvider(assembly))
   6:     .AddSingleton<IFileManager, FileManager>()
   7:     .BuildServiceProvider()
   8:     .GetService<IFileManager>()
   9:     .ReadAllTextAsync("data.txt").Result;
  10:  
  11: //直接讀取內嵌資原始檔
  12: Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.data.txt");
            
           

相關推薦

.NET Core檔案系統[1]讀取監控檔案變化

ASP.NET Core 具有很多針對檔案讀取的應用。比如我們傾向於採用JSON檔案來定義配置,所以應用就會涉及針對配置檔案讀取。如果使用者傳送一個針對物理檔案的HTTP請求,應用會根據指定的路徑讀取目標檔案的內容並對請求予以響應。在一個ASP.NET Core MVC應用中,針對View的動態編譯會涉及到根

[ASP.NET Core 3框架揭祕] 檔案系統[1]抽象的“檔案系統

ASP.NET Core應用 具有很多讀取檔案的場景,比如配置檔案、靜態Web資原始檔(比如CSS、JavaScript和圖片檔案等)以及MVC應用的View檔案,甚至是直接編譯到程式集中的內嵌資原始檔。這些檔案的讀取都需要使用到一個IFileProvider物件。IFileProvider物件構建了一個抽象

.NET Core檔案系統[4]由EmbeddedFileProvider構建的內嵌(資源)檔案系統

一個物理檔案可以直接作為資源內嵌到編譯生成的程式集中。藉助於EmbeddedFileProvider,我們可以統一的程式設計方式來讀取內嵌於某個程式集中的資原始檔,不過在這之前我們必須知道如何將一個專案檔案作為資源並嵌入到生成的程式集中。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中] 目錄一

.NET Core檔案系統[2]FileProvider是個什麼東西?

在《讀取並監控檔案的變化》中,我們通過三個簡單的例項演示從程式設計的角度對檔案系統做了初步的體驗,接下來我們繼續從設計的角度來繼續認識它。這個抽象的檔案系統以目錄的形式來組織檔案,我們可以利用它讀取某個檔案的內容,還可以對目標檔案試試監控並捕捉它的變化。這些基本的功能均由相應的FileProvider來提供,

.NET Core檔案系統[3]由PhysicalFileProvider構建的物理檔案系統

ASP.NET Core應用中使用得最多的還是具體的物理檔案,比如配置檔案、View檔案以及網頁上的靜態檔案,物理檔案系統的抽象通過PhysicalFileProvider這個FileProvider來實現,該型別定義在NuGet包“Microsoft.Extensions.FileProviders.Phy

.NET Core檔案系統[5]擴充套件檔案系統構建一個簡易版“雲盤”

FileProvider構建了一個抽象檔案系統,作為它的兩個具體實現,PhysicalFileProvider和EmbeddedFileProvider則分別為我們構建了一個物理檔案系統和程式集內嵌檔案系統。總的來說,它們針對的都是“本地”檔案,接下來我們通過自定義FileProvider構建一個“遠端”檔案

PCL學習(1讀取顯示PCD檔案

之前也斷斷續續看過很多關於PCL的程式碼,但是沒有自己動手寫過,真的自己動手寫才發現有很多問題,特此記錄一下學習過程中的程式碼,想要有進步所有程式碼還是要手打,不能複製貼上啊! 用的PCD檔案是自己之前用結構光的程式碼掃描生成的PCD檔案,環境是VS2017+PCL1.8.

[ASP.NET Core 3框架揭祕] 檔案系統[2]總體設計

在《抽象的“檔案系統”》中,我們通過幾個簡單的例項演示從程式設計的角度對檔案系統做了初步的體驗,接下來我們繼續從設計的角度來進一步認識它。這個抽象的檔案系統以目錄的形式來組織檔案,我們可以利用它讀取某個檔案的內容,還可以對目錄或者檔案實施監控並及時得到變化的通知。由於IFileProvider物件提供了針對檔

[ASP.NET Core 3框架揭祕] 檔案系統[3]物理檔案系統

ASP.NET Core應用中使用得最多的還是具體的物理檔案,比如配置檔案、View檔案以及作為Web資源的靜態檔案。物理檔案系統由定義在NuGet包“Microsoft.Extensions.FileProviders.Physical”中的PhysicalFileProvider來構建。我們知道Syste

[ASP.NET Core 3框架揭祕] 檔案系統[4]程式集內嵌檔案系統

一個物理檔案可以直接作為資源內嵌到編譯生成的程式集中。藉助於EmbeddedFileProvider,我們可以採用統一的程式設計方式來讀取內嵌的資原始檔,該型別定義在 “Microsoft.Extensions.FileProviders.Embedded”這個NuGet包中。在正式介紹EmbeddedFil

[ASP.NET Core 3框架揭祕] 配置[1]讀取配置資料[上篇]

提到“配置”二字,我想絕大部分.NET開發人員腦海中會立即浮現出兩個特殊檔案的身影,那就是我們再熟悉不過的app.config和web.config,多年以來我們已經習慣了將結構化的配置定義在這兩個XML格式的檔案之中。到了.NET Core的時代,很多我們習以為常的東西都發生了改變,其中就包括定義配置的方式

Atitit 分散式檔案系統 hdfs nfs fastfs 目錄 1. 分散式檔案系統 1 2. 什麼是FastDFS 1 2.1. FastDFS特性 1 2.1.1. fastdfs是否可在

Atitit 分散式檔案系統 hdfs nfs fastfs   目錄 1. 分散式檔案系統 1 2. 什麼是FastDFS 1 2.1. FastDFS特性: 1 2.1.1. fastdfs是否可在windows系統下安裝?可以的話,哪位可以..._百度知道 2

debian9安裝busybox,製作根檔案系統(1)

1,構建根檔案目錄 ##mkdir rootfs ##mkdir root home bin sbin etc dev usr lib tmp mnt sys proc ##mkdir usr/lib usr/bin 2,安裝busybox 2.1,下載busybox安裝包,https

SpringBoot讀取核心配置檔案application生成靜態工具類

SpringBoot:讀取核心配置檔案application並生成靜態工具類       通常在SpringBoot專案中,如果需要使用配置檔案中的配置屬性,在使用情況少的情況下,可以參下文章《Sprin

Atitit 分散式檔案系統 hdfs nfs fastfs 目錄 1. 分散式檔案系統 1 2. 什麼是FastDFS 1 2.1. FastDFS特性 1 2.1.1. fastdfs是否可在

Atitit 分散式檔案系統 hdfs nfs fastfs 目錄 分散式檔案系統 通過獨立檔案伺服器可以解決一些問題,如果某天儲存檔案的那臺服務突然down了怎麼辦?可能你會說,定時將檔案系統備份,這臺down機的時候,迅速切換到另一臺

Python+OGR庫學習(二)讀取點向量檔案,複製特定屬性值點另存為shp檔案

程式碼思路: 1、匯入相關庫包,切換到當前資料夾 2、註冊驅動,開啟點向量檔案,獲取圖層 3、建立輸出檔案,並獲取圖層(沒有屬性定義) 4、定義輸出圖層欄位屬性:假設已知檔案所有屬性欄位定義(即ID和cover) (1)讀取輸入檔案中某一要素 (2)獲取ID、cover欄位定義 (3

Python+OGR庫學習(一)讀取點向量檔案屬性值和座標,儲存為TXT(一行一個要素值)

程式碼思路: 1、匯入相關庫包,切換到當前資料夾 2、註冊驅動,開啟點向量檔案,獲取圖層 3、開啟待寫入TXT檔案 4、遍歷要素: (1)獲取當前要素‘ID’和‘cover’欄位屬性 (2)獲取當前點要素對應幾何物件和其座標值X,Y (3)將ID、cover、X、Y寫入TXT檔案 (

linux.1建立分割槽和檔案系統

Command (? for help): l 0700 Microsoft basic data 0c01 Microsoft reserved 2700 Windows RE 3000 ONIE boot 3001 ONIE config

SilverLight C#程式之讀取修改App.config檔案

1. 向專案新增app.config檔案:右擊專案名稱,選擇“新增”→“新增新建項”,在出現的“新增新項”對話方塊中,選擇“新增應用程式配置檔案”;如果專案以前沒有配置檔案,則預設的檔名稱為“app.config”,單擊“確定”。出現在設計器檢視中的app.config檔案為

.NET Core在類庫中讀取配置文件appsettings.json

http sco erl serve clas mda don def top   在.NET Framework框架時代我們的應用配置內容一般都是寫在Web.config或者App.config文件中,讀取這兩個配置文件只需要引用System.Configuration程