<p>C# WebAssembly目前不支持WASI文件系统,.NET 8的wasm输出仅限浏览器沙箱环境,调用System.IO会抛PlatformNotSupportedException;替代方案包括InputFile组件、JS文件保存API、MemoryStream内存模拟及localStorage持久化。</p>

WASI在C# WebAssembly中根本不可用
目前(2024年中)没有任何主流C#编译到WebAssembly的工具链支持WASI文件系统。.NET 8 的 dotnet publish -t wasm 输出的是纯浏览器环境的 wasm,它运行在 JS 沙箱里,没有 WASI 运行时,wasi_snapshot_preview1 导入函数完全不存在,调用 System.IO.File 或 FileStream 会直接抛出 PlatformNotSupportedException。
C# WASM里读写“文件”的实际替代方案
浏览器不给 wasm 直接访问本地文件系统的权限,所有“文件操作”都得绕道 JS API 或内存模拟:
- 读取用户选择的文件:用
InputFile组件(Blazor WebAssembly),拿到IBrowserFile后用OpenReadStream()→ 转成MemoryStream或StreamReader - 保存文件到用户设备:调用 JS 的
saveAs(需引入file-saver.js)或URL.createObjectURL+<a download> - 模拟临时文件系统:用
System.IO.MemoryStream+System.IO.StringWriter做内存内读写,适合配置、缓存、中间数据处理 - 持久化小数据:存到
localStorage(JS 侧)或用Microsoft.JSInterop封装读写逻辑,但注意大小限制(~5MB)和字符串-only
为什么有人误以为C# WASM能用WASI
混淆主要来自三处:
- 把
dotnet.wasm和通用 wasm 运行时(如 Wasmtime)搞混——后者才支持 WASI,而 .NET 的 wasm 是专为浏览器定制的,没链接wasi_unstable导入表 - 看到 Rust/Go 编译的 wasm 支持 WASI,就默认 C# 也能,但 .NET Runtime 没实现
WasiHost接口,也未暴露__wasi_path_open等符号 - 尝试手动 patch
dotnet.wasm加入 WASI 导入——会导致 .NET GC 和异常机制崩溃,因为运行时底层依赖 JS 托管环境,不是标准 WASI host 兼容的
如果真需要跨平台文件抽象,该怎么做
别硬套 WASI,改用可注入的抽象层:
- 定义接口如
IFileSystem,包含ReadAllTextAsync(string path)、WriteAllTextAsync(string path, string content) - 在 Blazor WASM 中注入 JS-backed 实现(例如调用
window.showOpenFilePicker()+ArrayBuffer处理) - 在 .NET Desktop / Server 中注入
PhysicalFileSystem,复用原生System.IO - 避免在共享代码里直接 new
FileStream或写死路径,否则编译时不会报错,运行时才炸
真正卡住的点从来不是“怎么调 WASI”,而是忘了浏览器安全模型根本不允许——所有文件交互必须显式由用户触发,且不能绕过 JS 层。这点比任何语法细节都关键。










