MAUI Blazor学习12-文件另存为
MAUI Blazor学习12-文件另存为
MAUI Blazor系列目录
- MAUI Blazor学习1-移动客户端Shell布局 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习2-创建移动客户端Razor页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习3-绘制ECharts图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习4-绘制BootstrapBlazor.Chart图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习5-BLE低功耗蓝牙 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习6-扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习7-实现登录跳转页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习8-支持多语言 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习9-VS Code开发调试MAUI入门 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习10-BarcodeScanner扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习11-百度地图定位 - SunnyTrudeau - 博客园 (cnblogs.com)
PC软件经常有处理本机文件的功能,需要打开文件,文件另存为,打开目录等功能,例如Winform、WPF、UWP都能很方便的调用Microsoft.Win32.SaveFileDialog实现文件另存为功能。MAUI是跨平台框架,不能简单的调用win32的组件。MAUI Blazor运行在浏览器里边,需要借助html和JavaScript访问本机文件。本文研究一下实现文件另存为功能的不同方案。
继续沿用之前的MAUI Blazor项目MaBlaApp,增加文件另存为功能。
JavaScript的window.showSaveFilePicker方案
参考文档
Window:showSaveFilePicker() 方法 - Web API 接口参考 | MDN (mozilla.org)
js showOpenFilePicker showSaveFilePicker showDirectoryPicker API - Ajanuw - 博客园 (cnblogs.com)
编写JavaScript模块,把字符串另存为txt文件。
D:\Software\gitee\mauiblazorapp\MaBlaApp\wwwroot\js\FileDialog.js
//另存为txt文件 //https://developer.mozilla.org/zh-CN/docs/Web/API/Window/showSaveFilePicker //https://developer.mozilla.org/zh-CN/docs/Web/API/FileSystemFileHandle export async function SaveAsTxtFile(filename, contents) { //显示文件选择器,返回FileSystemFileHandle const fileHandle = await window.showSaveFilePicker({ suggestedName: filename, types: [ { description: "txt文件", accept: { "text/plain": [".txt"] } }] }); //创建一个 FileSystemWritableFileStream 用来写入 const writable = await fileHandle.createWritable(); //将文件内容写入到流中 await writable.write(contents); //关闭文件并将内容写入磁盘 await writable.close(); }
CommunityToolkit的FileSaver.SaveAsync方案
NET MAUI社区提供一个扩展组件来支持跨平台另存文件功能,开源的好处体现在这里,官方没有做好的,社区能弥补一下。
FileSaver - .NET MAUI 社区工具包 - Community Toolkits for .NET | Microsoft Learn
参考官网的DEMO写代码即可,非常简单。
D:\Software\gitee\mauiblazorapp\MaBlaApp\Pages\FileDialog.razor
//另存为txt文件(CommunityToolkit) private async Task SaveAsTxtFileByToolkit() { cts = new CancellationTokenSource(); CancellationToken cancellationToken = cts.Token; string filename = $"{DateTimeOffset.Now:yyyyMMdd-HHmmss}.txt"; using var stream = new MemoryStream(Encoding.UTF8.GetBytes(message)); var fileSaverResult = await fileSaver.SaveAsync(filename, stream, cancellationToken); if (fileSaverResult.IsSuccessful) { await Toast.Make($"The file was saved successfully to location: {fileSaverResult.FilePath}").Show(cancellationToken); } else { await Toast.Make($"The file was not saved successfully with error: {fileSaverResult.Exception.Message}").Show(cancellationToken); } }
Razor页面调用文件另存为
编写一个页面,采用隔离JavaScript组件的方案调用JavaScript模块的SaveAsTxtFile,直接调用CommunityToolkit的的方案。
D:\Software\gitee\mauiblazorapp\MaBlaApp\Pages\FileDialog.razor
@page "/filedialog" @implements IAsyncDisposable @inject IJSRuntime JS @using CommunityToolkit.Maui.Alerts; @using CommunityToolkit.Maui.Storage @using System.Text; @inject IFileSaver fileSaver <h3>打开本机文件和目录对话框</h3> <ul class="list-group"> <li class="list-group-item"> <button type="button" class="btn btn-primary btn-sm" @onclick=SaveAsTxtFileByJavaScript>另存为txt文件(JavaScript)</button> </li> <li class="list-group-item"> <button type="button" class="btn btn-primary btn-sm" @onclick=SaveAsTxtFileByToolkit>另存为txt文件(CommunityToolkit)</button> </li> </ul> <textarea class="m-2" style="height:100px;" @bind=message></textarea> @code { private IJSObjectReference? module; private string message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}, 你好,MAUI Blaor"; private CancellationTokenSource? cts; protected override async Task OnAfterRenderAsync(bool firstRender) { base.OnAfterRender(firstRender); if (firstRender) { module = await JS.InvokeAsync<IJSObjectReference>("import", "./js/filedialog.js"); } } //另存为txt文件(JavaScript) private async void SaveAsTxtFileByJavaScript() { string filename = $"{DateTimeOffset.Now:yyyyMMdd-HHmmss}.txt"; try { //另存为txt文件,默认utf8 await module!.InvokeVoidAsync("SaveAsTxtFile", filename, message); } catch (Exception ex) { Console.WriteLine(ex); } } //另存为txt文件(CommunityToolkit) private async Task SaveAsTxtFileByToolkit() { cts = new CancellationTokenSource(); CancellationToken cancellationToken = cts.Token; string filename = $"{DateTimeOffset.Now:yyyyMMdd-HHmmss}.txt"; using var stream = new MemoryStream(Encoding.UTF8.GetBytes(message)); var fileSaverResult = await fileSaver.SaveAsync(filename, stream, cancellationToken); if (fileSaverResult.IsSuccessful) { await Toast.Make($"The file was saved successfully to location: {fileSaverResult.FilePath}").Show(cancellationToken); } else { await Toast.Make($"The file was not saved successfully with error: {fileSaverResult.Exception.Message}").Show(cancellationToken); } } async ValueTask IAsyncDisposable.DisposeAsync() { if (module is not null) { await module.DisposeAsync(); } } }
测试
在windows上面使用VS2022调试运行,功能都是可以实现的,但是JavaScript的SaveAsTxtFile有时候闪退,CommunityToolkit的方案比较稳定,也可能是我的JavaScript代码不完善,水平有限。
考虑到手机APP一般没有读写本机文件的应用场景,所以不再手机上测试了。
结论
推荐用CommunityToolkit的文件另存为方案。
DEMO代码地址:https://gitee.com/woodsun/mauiblazorapp