在Blazor WebAssembly项目中,C#代码最终会被编译成WebAssembly在浏览器沙箱里运行,它无法直接访问用户电脑的任意文件路径。所有文件读写都必须经过浏览器提供的文件系统接口,并由用户主动授权。C#侧主要通过JavaScript互操作(JS Interop)来调用这些接口,再把数据以流或字节数组的形式传回托管堆处理。

使用InputFile组件选择文件
Blazor内置的InputFile组件是最简单的文件入口。它在底层封装了HTML的<input type="file">元素,当用户输入文件后会触发OnChange事件,并给出IBrowserFile接口实例。该接口允许我们打开一个只读流,C#可以像操作普通Stream一样读取内容。
需要注意,IBrowserFile.OpenReadStream默认有大小限制,且读取过程应是异步的,否则会阻塞UI线程。下面的示例展示了如何把用户选中的文本文件读入字符串并在页面显示。
@page "/upload"
@using Microsoft.AspNetCore.Components.Forms
@inject IJSRuntime JSRuntime
<InputFile OnChange="HandleFileSelected" />
<p>@fileContent</p>
@code {
private string fileContent;
private async Task HandleFileSelected(InputFileChangeEventArgs e)
{
var file = e.File;
using var stream = file.OpenReadStream();
using var reader = new System.IO.StreamReader(stream);
fileContent = await reader.ReadToEndAsync();
}
}
这种方式的优点是开发成本低,完全在C#中完成逻辑;缺点是无法写入本地磁盘,只能把文件保留在内存或传到服务器。如果用户希望把处理结果保存回原文件,就必须使用更底层的File System Access API。
通过JS互操作调用File System Access API
现代浏览器提供了window.showSaveFilePicker和window.showOpenFilePicker等接口,可以在用户确认后获得真实的文件句柄。由于这些API尚未被Blazor直接封装,我们需要写一段JavaScript,再用IJSRuntime.invokeAsync调用它。
下面的JS函数负责弹出保存对话框并把C#传来的文本写入文件。注意写入操作在JS侧完成,C#只负责准备字符串内容,这样能减少大对象跨边界拷贝。
window.saveTextToFile = async function (text) {
const opts = {
types: [{
description: 'Text file',
accept: { 'text/plain': ['.txt'] }
}]
};
const handle = await window.showSaveFilePicker(opts);
const writable = await handle.createWritable();
await writable.write(text);
await writable.close();
};
C#侧只需要注入IJSRuntime并异步调用即可。这样用户点击按钮后,浏览器会询问保存位置,选定后文件即被写入,整个过程C#没有触碰任何绝对路径。
@page "/save"
@inject IJSRuntime JSRuntime
<button @onclick="SaveClicked">保存文件</button>
@code {
private async Task SaveClicked()
{
string content = "来自C# WebAssembly的生成内容";
await JSRuntime.InvokeVoidAsync("saveTextToFile", content);
}
}
内存与性能注意事项
在WASM中,C#和JavaScript分属不同堆,传递大文件时会产生拷贝。若文件达到几十MB,建议用DotNetStreamReference把Stream直接交给JS读取,而不是先转成byte数组。如下示例展示了如何把C#的MemoryStream传给JS侧循环读取。
var ms = new System.IO.MemoryStream();
// 假设已写入数据
ms.Position = 0;
await JSRuntime.InvokeVoidAsync("readDotNetStream",
new Microsoft.JSInterop.DotNetStreamReference(ms));
对应JS函数通过getStreamManager读取分块,避免一次性占用过多内存。实际项目中还应捕获用户取消授权导致的异常,并给出友好提示,保证文件交互流程稳定。
| 方案 | 写入本地 | 开发复杂度 |
|---|---|---|
| InputFile | 否 | 低 |
| File System Access API | 是 | 中 |
综合来看,C#在WASM中与浏览器文件系统交互的核心就是“托管代码发指令,浏览器执行授权IO”。合理选择组件和API,就能在安全保障下完成丰富的文件处理功能。
C#_WebAssembly浏览器文件系统Blazor文件API修改时间:2026-08-08 02:33:29