前言:
在.Net Core中文件系统,不管是物理的PhysicalFileProvider
还是嵌入的EmbeddedFileProvider
都实现了IFileProvider
这个接口。
在使用时不仅能读取各种类型文件,还能使用IChangeToken
监控文件的变化。
> # 输入命令从 NuGet 安装
> Install-Package Microsoft.Extensions.FileProviders.Embedded
> Install-Package Microsoft.Extensions.FileProviders.Physical
> # or
> dotnet add package Microsoft.Extensions.FileProviders.Embedded
> dotnet add package Microsoft.Extensions.FileProviders.Physical
一、指定文件系统的位置
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;
}
}