讲师中心 微信公众号
AI工具推荐 视频效率加速

C# 实现自己的虚拟文件系统 C#如何创建一个内存或数据库支持的IFileProvider

雨婷同学_7767

雨婷同学_7767

发布时间:2026-02-17 08:30:11

|

569人浏览过

|

来源于php中文网

原创

IFileProvider 不能直接 new 因为它是抽象接口,.NET 未提供内存或数据库实现;需自定义实现 GetDirectoryContents、GetFileInfo 和 Watch 方法,并注意线程安全、路径大小写及同步/异步兼容性。

c# 实现自己的虚拟文件系统 c#如何创建一个内存或数据库支持的ifileprovider

为什么 IFileProvider 不能直接 new 出来

因为 IFileProvider 是抽象接口,.NET 没提供开箱即用的内存或数据库实现。你看到的 PhysicalFileProvider 或 EmbeddedFileProvider 都只负责读取物理路径或程序集资源,不支持写入、动态挂载或持久化到数据库。

想用内存或数据库做后端,必须自己实现 IFileProvider 和配套的 IFileInfo —— 这不是配置问题,是补全缺失抽象的责任。

  • 常见错误现象:new PhysicalFileProvider("memory://") 报错或静默失败,因为协议前缀不被识别
  • 根本原因:所有内置 IFileProvider 实现都依赖 System.IO,而 System.IO 不处理内存/DB 路径语义
  • 关键点:你得重写 GetDirectoryContents、GetFileInfo、Watch 三个方法,其中 Watch 在内存场景可返回空实现

内存版 IFileProvider 怎么写才不崩

核心是用 ConcurrentDictionary<string byte></string> 存文件内容,再套一层线程安全的 IFileInfo 实现。别用 Dictionary,并发读写会丢数据;也别在 GetFileInfo 里每次 new 对象,容易 GC 压力大。

示例关键片段:

C#
C#

"避开 C# 常见错误——空陷阱、异步陷阱、LINQ 陷阱及资源泄漏。"

下载
public class MemoryFileProvider : IFileProvider
{
    private readonly ConcurrentDictionary<string, byte[]> _files = new();

    public IDirectoryContents GetDirectoryContents(string subpath)
    {
        var entries = _files.Keys
            .Where(k => k.StartsWith(subpath + "/", StringComparison.Ordinal))
            .Select(k => new MemoryFileInfo(k, _files[k]))
            .ToArray();
        return new MemoryDirectoryContents(entries);
    }

    public IFileInfo GetFileInfo(string subpath) =>
        _files.TryGetValue(subpath, out var data)
            ? new MemoryFileInfo(subpath, data)
            : new NotFoundFileInfo(subpath);
}
  • subpath 传进来默认不带开头斜杠,但你的内存 key 可以统一存为 "wwwroot/index.html" 这种格式,别自动拼 /
  • 注意大小写:Windows 下路径不区分大小写,但 ConcurrentDictionary 默认区分,建议用 StringComparer.OrdinalIgnoreCase 构造
  • MemoryFileInfo 必须实现 Exists、Length、CreateReadStream,其中 CreateReadStream 返回 new MemoryStream(data),别复用同一份 MemoryStream

数据库支持的 IFileProvider 要绕过哪些坑

数据库本质是异步 IO,但 IFileProvider 全是同步方法。硬塞 GetAwaiter().GetResult() 会死锁(尤其在 ASP.NET Core 请求上下文中)。唯一安全做法:用同步 DB 驱动(如 SQLite 的 Microsoft.Data.Sqlite 同步 API),或者把 DB 层包装成同步假象。

  • 别用 EntityFrameworkCore 直接查:它没有同步查询入口,强行 .Result 在 IIS 或 Kestrel 下极易卡主线程
  • 表结构至少要字段:Path NVARCHAR(450) PRIMARY KEY、Content BLOB、LastModified DATETIME2;Path 建唯一索引,否则 GetFileInfo 查太慢
  • GetDirectoryContents 不能用 LIKE 'prefix%' 模糊查——路径有层级,得按 / 分割后做前缀树或递归 CTE,简单做法是加一列 ParentPath 存上级目录
  • 如果文件可能超 10MB,别把 Content 字段全 load 到内存再给 CreateReadStream,改用 SqliteCommand 的 ExecuteReader(CommandBehavior.SequentialAccess) 流式读取

IFileProvider 替换进 ASP.NET Core 时为啥静态文件不生效

因为 UseStaticFiles() 默认只认 IWebHostEnvironment.WebRootFileProvider,你 new 好的自定义 provider 得显式塞进去,不是注册到 DI 容器就完事。

  • 正确姿势:services.AddSingleton<ifileprovider>(sp => new DatabaseFileProvider(...));</ifileprovider> 注册,然后在 Configure 里:app.UseStaticFiles(new StaticFileOptions { FileProvider = app.ApplicationServices.GetRequiredService<ifileprovider>() });</ifileprovider>
  • 容易忽略:如果你还用了 UseSpa() 或 UseBlazorServer(),它们内部也会创建自己的 FileProvider,得看文档找对应选项覆盖,比如 spa.Options.SourcePath 是路径,不是 provider
  • 调试技巧:在自定义 GetFileInfo 开头加 Console.WriteLine($"GetFileInfo({subpath})"),启动后访问 /favicon.ico,看有没有输出——没输出说明根本没走到你的 provider

最麻烦的其实是 Watch 机制:内存和数据库都没法高效监听变更,ChangeToken.OnChange 那套得你自己用定时轮询或 DB 触发器模拟,生产环境慎用。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

相关专题

更多
硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3228

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

5329

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3869

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

486

2026.01.19

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

1967

2023.09.19

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4678

2023.08.10

console接口是干嘛的
console接口是干嘛的

console接口是一种用于在计算机命令行或浏览器开发工具中输出信息的工具,提供了一种简单的方式来记录和查看应用程序的输出结果和调试信息。本专题为大家提供console接口相关的各种文章、以及下载和课程。

916

2023.08.08

console.log是什么
console.log是什么

console.log 是 javascript 函数,用于在浏览器控制台中输出信息,便于调试和故障排除。想了解更多console.log的相关内容,可以阅读本专题下面的文章。

6883

2024.05.29

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

20

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn