网站建设需求分析范例,自适应网站模板怎么做,网站上的flv视频看不了,微信公众号免费模板素材网站ASP.NET Core应用 具有很多读取文件的场景#xff0c;比如配置文件、静态Web资源文件#xff08;比如CSS、JavaScript和图片文件等#xff09;以及MVC应用的View文件#xff0c;甚至是直接编译到程序集中的内嵌资源文件。这些文件的读取都需要使用到一个IFileProvider对象。… ASP.NET Core应用 具有很多读取文件的场景比如配置文件、静态Web资源文件比如CSS、JavaScript和图片文件等以及MVC应用的View文件甚至是直接编译到程序集中的内嵌资源文件。这些文件的读取都需要使用到一个IFileProvider对象。IFileProvider对象构建了一个抽象的文件系统我们不仅可以利用它提供的统一API来读取各种类型的文件还能及时监控目标文件的变化。一、树形层次结构IFileProvider对象为我们构建了一个具有层次化目录结构的文件系统。由于IFileProvider是一个接口所以由它构建的是一个抽象化的文件系统这里所谓的目录和文件都是一个抽象的概念。具体的文件可能对应一个物理文件也可能保存在数据库中或者来源于网络甚至有可能根本就不存在其内容需要在读取时动态生成。目录也仅仅是组织文件的逻辑容器。为了让读者朋友们对这个文件系统有一个大体认识我们先来演示几个简单的实例。文件系统管理的所有文件以目录的形式进行组织一个IFileProvider对象可以视为针对一个根目录的映射。目录除了可以存放文件之外还可以包含子目录所以目录/文件在整体上呈现出树形化层次化结构。接下来我们将一个IFileProvider对象映射到一个物理目录并利用它将所在目录的结构呈现出来。我们演示实例是一个普通的控制台程序。我们在演示实例中定义了如下一个IFileManager接口它利用一个唯一的ShowStructure方法将文件系统的整体结构显示出来。该方法具有一个类型为Actionint, string的参数负责将文件系统的节点目录或者文件名称呈现出来。这个Actionint, string对象的两个参数分别代表缩进的层级和目录/文件的名称。public interface IFileManager{ void ShowStructure(Actionint, string render);}我们定义如下这个FileManager类作为对IFileManager接口的默认实现它利用只读_fileProvider字段表示的IFileProvider对象来提取目录结构。目标文件系统的整体结构通过Render方法以递归的方式呈现出来其中涉及到对IFileProvider对象的GetDirectoryContents方法的调用。该方法返回一个IDirectoryContents对象表示指定目录的内容如果对应的目录存在我们可以遍历该对象得到它的子目录和文件。目录和文件最终体现为一个IFileInfo对象来至于IFileInfo对象对应的就是一个目录还是一个文件则通过其IsDirectory属性来区分。public class FileManager : IFileManager{ private readonly IFileProvider _fileProvider; public FileManager(IFileProvider fileProvider) _fileProvider fileProvider; public void ShowStructure(Actionint, string render) { int indent -1; Render(); void Render(string subPath) { indent; foreach (var fileInfo in _fileProvider.GetDirectoryContents(subPath)) { render(indent, fileInfo.Name); if (fileInfo.IsDirectory) { Render(${subPath}\{fileInfo.Name}.TrimStart(\\)); } } indent--; } } }接下来我们构建一个本地物理目录“c:\test\”并按照如下图所示的结构在它下面创建相应的子目录和文件。我们会将这个目录映射到一个IFileProvider对象上并进一步利用它创建出上面这个FileManager对象。我们最终调用这个FileManager对象的ShowStructure方法将目录结构呈现出来。整个演示程序体现在如下的代码片段中。我们针对目录“c:\test\”创建了一个表示物理文件系统的PhysicalFileProvider对象并将其注册到创建的ServiceCollection对象上。除此之外ServiceCollection对象上还添加了针对IFileManager/FileManager的服务注册。class Program{ static void Main() { static void Print(int layer, string name) Console.WriteLine(${new string( , layer * 4)}{name}); new ServiceCollection() .AddSingletonIFileProvider(new PhysicalFileProvider(c:\test)) .AddSingletonIFileManager, FileManager() .BuildServiceProvider() .GetRequiredServiceIFileManager() .ShowStructure(Print); }}我们最终利用ServiceCollection生成的IServiceProvider对象得到FileManager对象并调用该对象的ShowStructure方法将PhysicalFileProvider对象映射的目录结构呈现出来。当我们运行该程序之后控制台上将呈现出如下图所示的输出结果该结果为我们展示了映射物理目录的真实结构。S501二、读取文件内容前面我们演示了如何利用IFileProvider对象将文件系统的结构完整地呈现出来接下来我们来演示如何利用它来读取一个物理文件的内容。我们为IFileManager定义如下一个ReadAllTextAsync方法以异步的方式读取指定文件内容方法的参数表示文件的路径。如下面的代码片段所示ReadAllTextAsync方法将指定的文件路径作为参数调用IFileProvider对象的GetFileInfo方法得到一个IFileInfo对象。我们最终调用这个IFileInfo对象的CreateReadStream方法得到读取文件的输出流进而得到文件的真实内容。public interface IFileManager{ ... Taskstring ReadAllTextAsync(string path);}public class FileManager : IFileManager{ ... public async Taskstring ReadAllTextAsync(string path) { byte[] buffer; using (var stream _fileProvider.GetFileInfo(path).CreateReadStream()) { buffer new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); } return Encoding.Default.GetString(buffer); }}假设我们依然将FileManager使用的IFileProvider映射为目录“c:\test\”现在我们在该目录中创建一个名为data.txt的文本文件并在该文件中任意写入一些内容。接下来我们在Main方法中编写了如下的程序利用依赖注入的方式得到FileManager对象并读取文件data.txt的内容。最终的调试断言旨在确定通过IFileProvider读取的确实就是目标文件的真实内容。S502class Program{ static async Task Main() { var content await new ServiceCollection() .AddSingletonIFileProvider(new PhysicalFileProvider(c:\test)) .AddSingletonIFileManager, FileManager() .BuildServiceProvider() .GetRequiredServiceIFileManager() .ReadAllTextAsync(data.txt); Debug.Assert(content File.ReadAllText(c:\test\data.txt)); }}三、内嵌文件系统我们一直在强调由IFileProvider结构构建的是一个抽象的具有目录结构的文件系统具体文件的提供方式取决于对具体的IFileProvider对象是怎样一个类型。我们演示实例定义的FileManager并没有限定具体使用何种类型的IFileProvider该对象是在应用中通过依赖注入的方式指定的。由于上面的应用程序注入的是一个PhysicalFileProvider对象所以我们可以利用它来读取对应物理目录下的某个文件。假设现在将这个data.txt直接以资源文件的形式编译到程序集中我们就需要使用另一个名为EmbeddedFileProvider的实现类型。现在我们直接将这个data.txt文件添加到控制台应用的项目根目录下。在默认的情况下当我们编译项目的时候这样的文件并不能成为内嵌到目标程序集的资源文件我们需要利用VS将该文件的“Build Action”属性按照如下所示的方式设置为“Embedded resource”。上图所示的设置将会体现在项目文件.csproj文件上。具体来说项目文件会以如下的形式添加一个EmbeddedResource元素将文件data.txt设置为内嵌到编译后生成的程序集的内嵌资源文件。Project SdkMicrosoft.NET.Sdk ... ItemGroup EmbeddedResource Includedata.txt/ /ItemGroup/Project我们编写了如下的程序来演示针对内嵌于程序集中的资源文件的读取。我们首先得到当前入口程序集并利用它创建了一个EmbeddedFileProvider对象它代替原来的PhysicalFileProvider对象被注册到ServiceCollection之中。我们接下来采用了完全一致的编程方式得到FileManager对象并利用它读取内嵌文件data.txt的内容。为了验证读取的目标文件准确无误我们采用直接读取资源文件的方式得到了内嵌文件data.txt的内容并利用一个调试断言确定两者的一致性。S503class Program{ static async Task Main() { var assembly Assembly.GetEntryAssembly(); var content1 await new ServiceCollection() .AddSingletonIFileProvider(new EmbeddedFileProvider(assembly)) .AddSingletonIFileManager, FileManager() .BuildServiceProvider() .GetRequiredServiceIFileManager() .ReadAllTextAsync(data.txt); var stream assembly.GetManifestResourceStream(${assembly.GetName().Name}.data.txt); var buffer new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); var content2 Encoding.Default.GetString(buffer); Debug.Assert(content1 content2); }}四、监控文件的变化在文件读取场景中确定加载到内存中的数据与源文件的一致性并自动同步是一个很常见的需求。比如说我们将配置定义在一个JSON文件中应用启动的时候会读取该文件并将其转换成对应的Options对象。在很多情况下如果我们改动了配置文件 最新的配置数据只有在应用重启之后才能生效。如果我们能够以一种高效的方式对配置文件进行监控并在其发生改变的情况下向应用发送通知那么应用就能在不用重启的情况下重新读取配置文件进而实现Options对象承载的内容和原始配置文件完全同步。对文件系统实施监控并在其发生改变时发送通知也是IFileProvider对象提供的核心功能之一。接下来我们依然使用前面这个程序来演示如何使用PhysicalFileProvider对某个物理文件实施监控并在目标文件的内容发生改变的时候重新读取新的内容。class Program{ static async Task Main() { using (var fileProvider new PhysicalFileProvider(c:\test)) { string original null; ChangeToken.OnChange(() fileProvider.Watch(data.txt), Callback); while (true) { File.WriteAllText(c:\test\data.txt, DateTime.Now.ToString()); await Task.Delay(5000); } async void Callback() { var stream fileProvider.GetFileInfo(data.txt).CreateReadStream(); { var buffer new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); string current Encoding.Default.GetString(buffer); if (current ! original) { Console.WriteLine(original current); } } } } }}如上面的代码片段所示我们针对目录“c:\test”创建了一个PhysicalFileProvider对象并调用其Watch方法对指定的文件data.txt实施监控。该方法的返回一个IChangeToken对象我们正是利用这个对象接收文件改变的通知。我们调用ChangeToken的静态方法OnChange针对这个对象注册了一个回调实现对源文件的重新读取和显示当源文件发生改变的时候注册的回调会自动执行。我们以每隔5秒的间隔对文件data.txt作一次修改而文件的内容为当前时间。所以当我们的程序启动之后每隔5秒钟当前时间就会以如下图的方式呈现在控制台上。