.Net Core 文件系统整理
一、.Net Core 文件系统说明
1. .Net Core中的文件系统不同于.Net Framework的逻辑
2. .Net Core 的默认文件系统,从当前程序的Dll所在文件夹开始。
3.如果使用系统绝对路径则需要借助 PhysicalFileProvider, 安装 Microsoft.Extensions.FileProviders.Physical 程序集。
二、 安装依赖
在.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; } }
更多:
.Net Core 异常 System.IO.IOException:“文件名、目录名或卷标语法不正确。