本文章介绍在 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
评论