IFileManagerFileManager : IFileManager[] buffer;[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.0.0", 10: "Microsoft.Extensions.FileProviders.Embedded" : "1.0.0" 11: }, 12: ... 13: }
我们编写了如下的程序来演示针对内嵌于程序集中的资源文件的读取。我们首先得到当前入口程序集,并利用它创建了一个EmbeddedFileProvider,后者替换原来的PhysicalFileProvider对象被注册到ServiceCollection之上。我们接下来采用与上面完全一致的编程方式得到FileManager对象并利用它读取内嵌文件data.txt的内容。为了验证读取的目标文件准确无误,我们采用直接读取资源文件的方式得到了内嵌文件data.txt的内容,并利用一个调试断言确定两者的一致性。
content1 = [] buffer = content2 = Encoding.ASCII.GetString(buffer); 16: 17: Debug.Assert(content1 == content2);
五、监控文件的变化
在文件读取场景中,应用数据与源文件的同步是一个很常见的需求。比如说我们将配置定义在一个JSON文件中,应用启动的时候会读取该文件并根据配置数据对应用作相应的设置。在很多情况下,如果我们改动了配置文件, 最新的配置数据只有在应用重启之后才能生效。如果我们能够以一种高效的方式对配置文件进行监控,并在其发生改变的情况下相应用发送通知,那么应用就能在不用重启的情况下重新读取配置文件,进而实现应用配置和原始配置文件的同步。
对文件系统试试监控并在发生改变时发送通知也是FileProvider对象的核心功能之一。接下来我们依然使用上面这个控制台文件来演示如何使用PhysicalFileProvider来对某个物理文件试试监控,并在目标文件的内容发生改变的时候重新读取新的内容。定义在Main方法上的整个程序代码如下所示。
ProgramMain(async [stream.Length]; 19: await stream.ReadAsync(buffer, 0, buffer.Length); 20: Console.WriteLine(Encoding.ASCII.GetString(buffer)); 21: } 22: } 23: }
如上面的代码片段所示,我们针对目录“c:\test”创建了一个PhysicalFileProvider,并调用Watch方法对指定的文件data.txt实施监控。该方法的返回类型为IChangeToken,我们正式利用这个对象接收文件改变的通知。我们调用ChangeToken的静态方法OnChange针对这个对象注册了一个回调,意味着当源文件发生改变的时候,注册的回调会自动执行,进而实现对源文件的重新读取和显示。在程序的末端,我们以每隔5秒的间隔对文件data.txt作一次修改,而文件的内容为当前时间。所以当我们的程序启动之后,每隔5秒钟当前时间就会以如下的方式呈现在控制台上。