首页 > 编程语言 >《ASP.NET Core 6 框架揭秘》第四章读书笔记 - 文件系统

《ASP.NET Core 6 框架揭秘》第四章读书笔记 - 文件系统

时间:2022-12-12 18:14:13浏览次数:56  
标签:IChangeToken Core ASP 文件 对象 IFileProvider 读书笔记 Summary file

IFileProvider 对象构建了一个抽象的文件系统,我们不仅可以利用该系统提供的统一 API 读取各种类型的文件,还能及时监控目标文件的变化。

 

4.1 抽象的文件系统

IFileProvider 对象用于构建一个具有层次化目录结构的抽象文件系统,该系统中的目录和文件都是一个抽象的概念。

 

4.1.1 树形层次结构

一个 IFileProvider 对象可以视为针对一个目录的映射。

增加 Microsoft.Extensions.FileProviders.Physical  NuGet 包:dotnet add package Microsoft.Extensions.FileProviders.Physical,这个包提供了物理文件系统的实现。

IFileProvider#GetDirectoryContents 方法返回一个表示“目录内容”的 IDirectoryContents 对象。如果对应的目录存在,可遍历所有子目录和文件,目录和文件体现为一个 IFileInfo 对象,通过 IsDirectory 属性判断是目录还是文件。

GetDirectoryContents 返回一个 IDirectoryContents 对象,具体定义如下:

 1    //
 2     // Summary:
 3     //     Represents a directory's content in the file provider.
 4     public interface IDirectoryContents : IEnumerable<IFileInfo>, IEnumerable
 5     {
 6         //
 7         // Summary:
 8         //     True if a directory was located at the given path.
 9         bool Exists { get; }
10     }

从定义看实现了 IEnumerable<IFileInfo> 接口,因此可以用 froeach 循环。

 

4.1.2 读取文件内容

IFileProvider#GetFileInfo 方法可以得到一个描述目标文件的 IFileInfo 对象,再调用 IFileInfo#CreateReadStream 得到输出流。

 1   static async Task MainAsync(){
 2             IServiceProvider provider = new ServiceCollection()
 3                     .AddSingleton<IFileProvider>(new PhysicalFileProvider(@"D:\repository\Core\FirstCore"))  //
 4                     .AddSingleton<IFileSystem, FileSystem.FileSystem>()
 5                     .BuildServiceProvider();
 6 
 7             var content = await provider.GetRequiredService<IFileSystem>().ReadAllTextAsync(@"cities.txt");
 8             Debug.Assert(content == File.ReadAllText(@"D:\repository\Core\FirstCore\cities.txt"));
 9     }
10 
11   static void Print(int layer, string name)
12                 => Console.WriteLine($"{new string(' ', layer * 4)}{name}");

 

4.1.3 监控文件的变化

对文件系统实施监控并在其发生改变时发送通知也是 IFileProvider 提供的核心功能之一。

 1   var fileProvider = new PhysicalFileProvider(@"d:\");
 2             string? original = null;
 3 
 4             ChangeToken.OnChange(() => fileProvider.Watch("test.txt"), Callback);
 5 
 6             while(true){
 7                 File.WriteAllText(@"d:\test.txt", DateTime.Now.ToString());
 8                 await Task.Delay(5000);
 9             }
10 
11             async void Callback(){
12                 var stream = fileProvider.GetFileInfo("test.txt").CreateReadStream();
13                 {
14                     var buffer = new byte[stream.Length];
15                     await stream.ReadAsync(buffer);
16 
17                     var current = Encoding.Default.GetString(buffer);
18                     if(current != original){
19                         Console.WriteLine(original = current);
20                     }
21                 }
22             }

上面代码中,使用 IFileProvider 对象的 Watch 方法监控指定的文件,该方法会利用返回的  IChangeToken 对象发送文件更新的通知。调用 ChangeToken 的静态方法 OnChange 给 IChangeToken 对象注册了一个回调。

后面有讲到 IChangeToken 只能使用一次,这里为什么可以一直监控?

 

 

4.2 文件与目录

接下来从设计的角度对文件系统进行系统的介绍。

文件系统更新的通知是由一个 IChangeToken 对象发出来的。

 

4.2.1 IChangeToken 

IChangeToken 传播已发生更改的通知。 IChangeToken 驻留在 Microsoft.Extensions.Primitives 命名空间中。

IChangeToken 具有以下两个属性:

  1)ActiveChangeCallbacks,当数据发生变化时指示令牌是否主动引发回调。

  2)HasChanged,接收一个指示是否发生更改的值。

IChangeToken 接口具有 RegisterChangeCallback(Action<Object>, Object) 方法,用于注册在令牌更改时调用的回调。该方法会返回一个 IDisposable 对象,可以用其 Dispose 方法解除回调。

常使用的 IChangeToken 的实现类型是 CancellationChangeToken,它是对一个 CancellationToken 对象的封装。

还有 CompositeChangeToken,它表示由多个 IChangeToken 组合而成的复合型 IChangeToken 对象。只要组成它的任何一个 IChangeToken 发生改变,其 HasChanged 就为 True,注册的回调随之被执行。只要任何一个 IChangeToken 的同名属性返回 True,ActiveChangeCallbacks 就为 True。

由于 IChangeToken 对象没有状态“复位”功能,所以变更一旦发生,它的使命就完成了,下次变更检测将交给新创建的 IChangeToken 对象。

 

4.2.2 IFileProvider

IFileProvider 有 3 个核心方法。

 1    //
 2     // Summary:
 3     //     A read-only file provider abstraction.
 4     public interface IFileProvider
 5     {
 6         //
 7         // Summary:
 8         //     Enumerate a directory at the given path, if any.
 9         //
10         // Parameters:
11         //   subpath:
12         //     Relative path that identifies the directory.
13         //
14         // Returns:
15         //     Returns the contents of the directory.
16         IDirectoryContents GetDirectoryContents(string subpath);
17         //
18         // Summary:
19         //     Locate a file at the given path.
20         //
21         // Parameters:
22         //   subpath:
23         //     Relative path that identifies the file.
24         //
25         // Returns:
26         //     The file information. Caller must check Exists property.
27         IFileInfo GetFileInfo(string subpath);
28         //
29         // Summary:
30         //     Creates a Microsoft.Extensions.Primitives.IChangeToken for the specified filter.
31         //
32         // Parameters:
33         //   filter:
34         //     Filter string used to determine what files or folders to monitor. Example: **/*.cs,
35         //     *.*, subFolder/**/*.cshtml.
36         //
37         // Returns:
38         //     An Microsoft.Extensions.Primitives.IChangeToken that is notified when a file
39         //     matching filter is added, modified or deleted.
40         IChangeToken Watch(string filter);
41     }

IFileInfo 对象可以用于描述目录和文件,但是 GetFileInfo 方法只为得到指定路径的文件而不是目录,无论指定的目录或者文件是否存在,GetFileInfo 和 GetDirectoryContents 一样,都会返回一个具体的 IFileInfo 或 IDirectoryContents,通过 Exists 属性确定是否存在。

 1    public interface IFileInfo
 2     {
 3         //
 4         // Summary:
 5         //     True if resource exists in the underlying storage system.
 6         bool Exists { get; }
 7         //
 8         // Summary:
 9         //     The length of the file in bytes, or -1 for a directory or non-existing files.
10         long Length { get; }
11         //
12         // Summary:
13         //     The path to the file, including the file name. Return null if the file is not
14         //     directly accessible.
15         string? PhysicalPath { get; }
16         //
17         // Summary:
18         //     The name of the file or directory, not including any path.
19         string Name { get; }
20         //
21         // Summary:
22         //     When the file was last modified
23         DateTimeOffset LastModified { get; }
24         //
25         // Summary:
26         //     True for the case TryGetDirectoryContents has enumerated a sub-directory
27         bool IsDirectory { get; }
28 
29         //
30         // Summary:
31         //     Return file contents as readonly stream. Caller should dispose stream when complete.
32         //
33         // Returns:
34         //     The file stream
35         Stream CreateReadStream();
36     }

IFileProvider#Watch 方法接收一个字符串类型的参数 filter,可以使用该参数指定一个“文件匹配模式”(File Globbing Pattern)表达式。这种表达式类似于正则表达式但比正则简单很多,它只包含“*”一种通配符。“*”表示路径分隔符之间的单个分段内的所有字符;“**”表示可以跨越多个路径分段的所有字符。

一般来说,调用 IFileProvider 的方法时所指定的目标文件或目录的路径,提供的是根目录的相对路径,指定的这个路径可以采用“/”作为前缀,但这个不是必需的。

 

4.2.3 两个特殊的文件系统

1. NullFileProvider

NullFileProvider 表示一个不包含任何目录和文件的文件系统,定义在 “Microsoft.Extensions.FileProviders” 命名空间中。

它的 GetDirectoryContents 和 GetFileInfo 分别返回 NotFoundDirectoryContents 和 NotFoundFileInfo 对象。空的文件系统不存在所谓的目录和文件变化,因此 Watch 方法返回一个 NullChangeToken 对象。

 

2. CompositeFileProvider

需要导入包:dotnet add package Microsoft.Extensions.FileProviders.Composite

CompositeFileProvider 表示一个由多个 IFileProvider 构建的复合式的文件系统,定义在 “Microsoft.Extensions.FileProviders” 命名空间中。

CompositeFileProvider 由多个 IFileProvider 对象构成,当调用 GetFileInfo 方法时,会遍历这些 IFileProvider 对象,直到找到一个存在的文件。如果都没有,那么返回一个 NoteFoundFileInfo 对象。遍历的顺序取决于构建 CompositeFileProvider 时提供的顺序,因为如果有优先级的要求,把优先级高的放在前面。

某个目录的内容是由所有这些内部 IFileProvider 对象共同提供的,GetDirectoryContents 返回的是 CompositeDirectoryContents。

 1       IFileProvider provider1 = new PhysicalFileProvider(@"d:\work\1");
 2         IFileProvider provider2 = new PhysicalFileProvider(@"d:\work\2");
 3         IFileProvider compositeProvider = new CompositeFileProvider(provider1, provider2);
 4         IDirectoryContents contents = compositeProvider.GetDirectoryContents("a");
 5 
 6         StringBuilder sb = new StringBuilder();
 7         
 8         foreach(var fileInfo in contents){
 9             sb.Append($"{fileInfo.PhysicalPath}\r\n");
10         }
11 
12         return sb.ToString();

如果多个 IFileProvider 对象存在一个具有相同路径的文件,则从优先提供的 IFileProvider 中提取。

 

 

4.3 物理文件系统

4.3.1 PhysicalFileInfo

一个 PhysicalFileProvider 总是映射到某个物理目录上,被映射的目录所在的路径通过构造函数的参数 root 提供。它的 GetFileInfo 方法返回的是 PhysicalFileInfo 对象表示指定路径的文件,PhysicalFileInfo 实际上是 FileInfo 的一个封装。

以下场景 GetFileInfo 方法返回 NotFoundFileInfo 对象:

  1)不存在与指定路径相匹配的物理文件;

  2)指定的是文件的绝对路径;

  3)目标文件为隐藏文件。

 

4.3.2 PhysicalDirectoryInfo

物理目录,是对 System.IO.DirectoryInfo 的封装。

Length 属性返回 -1.

 

4.3.3 PhsicalDirectoryContents

PhysicalFileProvider#GetDirectoryContents ,如果指定的路径指向一个具体的目录,返回 PhysicalDirectoryContents,后者是一组 IFileInfo 的集合,封装的 IFileInfo 要么是描述子目录的 PhysicalDirectoryInfo 对象,要么是描述物理文件的 PhysicalFileInfo 对象。

 

4.3.4 NotFoundDirectoryContents

如果指定的路径并不存在或者是一个绝对路径,则返回一个 Exists 属性为 false 的 NotFoundDirectoryContents 对象。

可以使用静态属性 Singleton 得到对应的单例对象。

 

4.3.5 PhysicalFilesWatcher

监控文件或者目录的变化都会实时反映到 Watch 方法返回的 IChangeToken 对象上。它是利用一个 FileSystemWatcher 对象来完成对指定根目录下子目录和文件的监控。

在 Watch 方法中指定的 Globbing Pattern 表达式必须是当前根目录的相对路径。

 

 

4.4 内嵌文件系统

EmbeddedFileProvider 可以使用统一的编程方式来读取内嵌的资源文件。该类型定义在“Microsoft.Extensions.FileProvider.Embedded” NuGet 包中。

 

4.4.1 将项目文件变成内嵌资源

要将静态文件作为目标程序集的内嵌文件,需要修改当前多项目的 .csproj 文件,在文件中添加<ItemGroup>/<EmbeddedResource>元素,并利用 Include 属性显式地把资源文件包含进来。

<EmbeddedResource> 节点的 Include 属性可以设置多个以分号分隔的路径,也可以使用通配符将一组文件包含进来。排除不符合要求的文件使用 Exclude 属性。

 

4.4.2 读取资源文件

一个程序集主要由两种类型的文件构成,即承载 IL 代码的托管模块文件和编译时内嵌的资源文件。程序集使用清单(Manifest)记录组成程序集的所有文件成员。

资源文件在程序集中是扁平化存储的,编译器会根据原始文件所在的路径对资源文件重新命名,具体规则是“{BaseNamespce}.{Path}”。

Assembly#GetManifestResourceNames:返回所有的资源文件名称。

 

标签:IChangeToken,Core,ASP,文件,对象,IFileProvider,读书笔记,Summary,file
From: https://www.cnblogs.com/fxb248/p/16969705.html

相关文章

  • 《Spring Boot+Vue全栈开发实战》读书笔记
    写在前面嗯,回家处理一些事,所以离职了,之前的公司用开源技术封装了一套自己的低代码平台,所以之前学的springBoot之类的东西都忘了很多,蹭回家的闲暇时间复习下。笔记整体以Sp......
  • 《Kubernetes权威指南:从Docker到Kubernetes实践全接触》读书笔记
    写在前面之前简单的了解过,但是机器的原因,只有单机,因为安装Docker的原因,本机VM上的红帽节点起不来了。懂得不多,视频上都是多节点的,所以教学视屏上的所以Demo没法搞。前些时间......
  • 《Java并发编程详解》读书笔记
    嗯,书是假期开始看的感觉,虽然部分知识以前学过,但是在学一次巩固一下。嗯,加油生活。摘一句子,^_^有一天,突然发现自己没有热爱的东西了。就这样进入浪费时间的年代。秋天一到,候......
  • 《从Paxos到Zookeeper分布式一致性原理与实践》读书笔记
    写在前面嗯,一直听人家说​​分布式​​​,奈何这个概念一直不清晰,而且问大佬,也总是听的一知半解的,一直听人家讲​​Zookeeper​​,很早就想系统的学习一下,奈何时间挤不出来,除......
  • 《ES6标准入门》读书笔记
         嗯,之前之做项目大概了解一些,之后看Vue实战里讲一些,简历里写了这个,所以决定系统学习,第一次接触大佬阮一峰是讲Flex布局的一篇博文,感觉很好,居然把书开源,嗯,......
  • 《Python核心编程》第三版 读书笔记
    “一个不成熟男子的标志是为了某种事业英勇地死去,一个成熟男子的标志是为了某种事业卑微地活着。”                       ......
  • 《JAVA8基础应用与开发》读书笔记
    第一章,JAVA技术体系架构JAVASE,(标准版),核心技术。小型桌面应用。 JAVAME,(微型版),嵌入式,电子产品程序。 JAVAEE,(企业版),web应用。涉及的技术面很广。计算机语言机制 ......
  • 《自然语言处理入门》读书笔记
    第一章,新手上路1.1自然语言与编程语言词汇量结构化:歧义性:容错性;易变性简略性1.2自然语言处理的层次文本:语音(语音识别),图像(光学符号识别),和文本。词法分析:中文分词(将......
  • 《Spring Cloud 微服务架构进阶》读书笔记
    前页随着DevOps和以Docker为主的容器技术的发展,云原生应用架构和微服务变得流行起来。云原生包含的内容很多,如DevOps、持续交付、微服务、敏捷等第一章,微服务架构介......
  • 【HMS Core】运动健康服务上传平台的健康数据,能否获取到上传设备的SN码或者唯一设备码
    ​ 问题描述上传平台的健康数据,能否获取到上传设备的SN码或者唯一设备码信息 解决方案DeviceInfo中包含华为设备唯一标识,您可以通过DeviceInfo进行查看。DeviceInfo......