本文章介绍在 ASP.NET Core 中使用文件提供程序来抽象化文件系统访问
介绍
文件提供程序的主接口为 IFileProvider,公开方法以实现以下目的
文件提供程序包有两个实现,分别是 物理文件 和 嵌入式文件
指定文件系统的位置
物理文件 PhysicalFileProvider 对象总是映射到某个具体的物理目录下
嵌入式文件 EmbeddedFileProvider 对象总是映射到某个具体的程序集中
// 指定物理文件系统的根目录 // 指定 F 盘的 Downloads 文件夹为根目录 IFileProvider physicalFileProvider = new PhysicalFileProvider(@"F:\Downloads");
// 指定嵌入文件系统的程序集 // 指定当前执行代码的程序集 IFileProvider embeddedFileProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly());
复制代码
文件系统的基本操作
文件系统中的的文件和文件夹都统一抽象为 IFileInfo
首先我们看 IFileProvider,IFileInfo,IDirectoryContents 的源码
public interface IFileProvider { // 获取指定子路径的文件信息 IFileInfo GetFileInfo(string subpath); // 获取指定子路径的所有内容 IDirectoryContents GetDirectoryContents(string subpath); // 用于监听文件改变 IChangeToken Watch(string filter); } public interface IFileInfo { bool Exists { get; } long Length { get; } string PhysicalPath { get; } string Name { get; } DateTimeOffset LastModified { get; } bool IsDirectory { get; } Stream CreateReadStream(); } public interface IDirectoryContents : IEnumerable<IFileInfo>, IEnumerable { bool Exists { get; } }
复制代码
根据源码,我们可以看到 IDirectoryContents 为 IEnumerable<IFileInfo>
IFileInfo 有属性 IsDirectory 和 Exists 来判断是否存在或是否为文件夹
IFileInfo 可以直接拿到一些基本信息,以及 Stream
// 例子: 获取 F:\Downloads\Text.txt 中的文本 var fileProvider = new PhysicalFileProvider(@"F:\Downloads"); await using var stream = fileProvider.GetFileInfo("Text.txt").CreateReadStream(); var buffer = new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); var result = Encoding.Default.GetString(buffer); // 例子: 读取嵌入文件的内容 var fileProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly()); await using var stream = fileProvider.GetFileInfo("Text.txt").CreateReadStream(); var buffer = new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); var result = Encoding.Default.GetString(buffer);
复制代码
文件系统的文件监听
争对文件变化监听可以是创建、修改、重命名和删除,都会触发 ChangeToken.OnChange 的第二个 Action 委托,即更改文件后的回调,下面代码监听的是 Text.txt 文件,当然你也可以在 Watch 方法中使用 文件通配
var physicalFileProvider = new PhysicalFileProvider(@"F:\Downloads"); // 通过表达式筛选需要监控的文件或目录(Watch可以使用例如 *.* 进行文件通配) ChangeToken.OnChange(() => physicalFileProvider.Watch("Text.txt"), async () => { Console.Clear(); IFileInfo fileInfo = physicalFileProvider.GetFileInfo("Text.txt"); await using var stream = fileInfo.CreateReadStream(); var buffer = new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); Console.WriteLine(Encoding.Default.GetString(buffer)); }); Console.Read();
复制代码
使用依赖注入
使用依赖注入需要引入 NuGet 包 Microsoft.Extensions.DependencyInjection
static async Task Main(string[] args) { // 读取普通文件夹资源 var provider = new ServiceCollection() .AddSingleton<IFileProvider>(new PhysicalFileProvider(@"F:\Downloads")) .AddSingleton<FileManager>() .BuildServiceProvider(); var fileManager = provider.GetService<FileManager>(); var content = await fileManager.ReadAsync("Text.txt"); Console.WriteLine(content); } public class FileManager { private readonly IFileProvider _fileProvider; public FileManager(IFileProvider fileProvider) { _fileProvider = fileProvider; } public async Task<string> ReadAsync(string path) { await using var stream = _fileProvider.GetFileInfo(path).CreateReadStream(); var buffer = new byte[stream.Length]; await stream.ReadAsync(buffer, 0, buffer.Length); var result = Encoding.Default.GetString(buffer); return result; } }
复制代码
参考文档
Microsoft.Extensions.FileProviders.Physical
评论