在Blazor页面中下载MemoryStream生成的TXT文件方案咨询
如何在Blazor中无临时文件下载MemoryStream中的ASCII艺术文件
这里提供两种无需创建服务器临时文件的解决方案,根据你的文件体积选择即可:
方案1:通过IJSRuntime调用JavaScript直接触发下载
无需额外接口,直接将ASCII文本内容传递给前端JS生成下载链接,适合大多数常规体积的文件。
步骤1:添加全局JavaScript函数
在项目的wwwroot/index.html(Blazor WebAssembly)或Pages/_Layout.cshtml(Blazor Server)中添加以下代码:
window.downloadFile = function (fileName, content, mimeType) { const blob = new Blob([content], { type: mimeType }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); };
步骤2:修改Blazor页面代码
调整文件上传后的处理逻辑,读取MemoryStream中的文本内容并调用JS函数:
@page "/" @using ClassLibraryTransformImageToAsciiArt; @using Microsoft.AspNetCore.Components.Forms @using System.Text; @inject IConvertImageToAsciiArt ConvertImageToAsciiArt @inject IJSRuntime jsRuntime <div class="container"> <h1>Transform Images To Ascii Art</h1> <InputFile OnChange="@OnInputFileChange" /> </div> @code { private long maxFileSize = 1024L * 1024L * 10L; //10 Mb private async Task OnInputFileChange(InputFileChangeEventArgs e) { using var imageStream = new MemoryStream(); await e.File.OpenReadStream(maxAllowedSize: maxFileSize).CopyToAsync(imageStream); imageStream.Position = 0; // 重置流位置,确保转换方法能读取完整内容 using var textFileStream = ConvertImageToAsciiArt.ConvertImageToAsciiArtStream(imageStream); textFileStream.Position = 0; // 重置流位置,准备读取ASCII内容 // 将流内容读取为ASCII字符串 var asciiContent = await new StreamReader(textFileStream, Encoding.ASCII).ReadToEndAsync(); // 调用JS函数触发下载,自定义文件名 await jsRuntime.InvokeVoidAsync("downloadFile", "ascii_art.txt", asciiContent, "text/plain"); } }
关键注意点
- 必须重置Stream的
Position为0,否则后续读取/转换会从流的末尾开始,导致内容为空 - 使用
using语句自动释放Stream资源,避免内存泄漏 - 直接传递文本字符串比base64编码更高效,适合文本类文件
方案2:通过GET接口返回文件(适合超大文件场景)
如果ASCII内容体积极大,直接传递字符串到前端可能有性能问题,可以通过内存缓存暂存流,再通过API接口返回:
步骤1:注册内存缓存服务
在Program.cs中添加缓存服务:
builder.Services.AddMemoryCache();
步骤2:创建下载API控制器
新建AsciiDownloadController.cs:
using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; [ApiController] [Route("api/[controller]")] public class AsciiDownloadController : ControllerBase { private readonly IMemoryCache _cache; public AsciiDownloadController(IMemoryCache cache) { _cache = cache; } [HttpGet("{fileId}")] public IActionResult Download(string fileId) { if (_cache.TryGetValue<MemoryStream>(fileId, out var stream)) { stream.Position = 0; // 下载完成后立即从缓存移除,释放内存 _cache.Remove(fileId); return File(stream, "text/plain", "ascii_art.txt"); } return NotFound(); } }
步骤3:修改Blazor页面代码
@page "/" @using ClassLibraryTransformImageToAsciiArt; @using Microsoft.AspNetCore.Components.Forms @using Microsoft.Extensions.Caching.Memory @using System.Guid; @inject IConvertImageToAsciiArt ConvertImageToAsciiArt @inject IJSRuntime jsRuntime @inject IMemoryCache _cache <div class="container"> <h1>Transform Images To Ascii Art</h1> <InputFile OnChange="@OnInputFileChange" /> </div> @code { private long maxFileSize = 1024L * 1024L * 10L; //10 Mb private async Task OnInputFileChange(InputFileChangeEventArgs e) { using var imageStream = new MemoryStream(); await e.File.OpenReadStream(maxAllowedSize: maxFileSize).CopyToAsync(imageStream); imageStream.Position = 0; // 缓存存储的流不能用using,后续由控制器处理释放 var textFileStream = ConvertImageToAsciiArt.ConvertImageToAsciiArtStream(imageStream); textFileStream.Position = 0; // 生成唯一ID标识缓存中的文件 var fileId = Guid.NewGuid().ToString(); // 设置5分钟过期时间,避免内存长期占用 _cache.Set(fileId, textFileStream, TimeSpan.FromMinutes(5)); // 调用JS打开下载链接 await jsRuntime.InvokeVoidAsync("open", $"/api/AsciiDownload/{fileId}", "_blank"); } }
关键注意点
- 必须设置缓存过期时间,防止内存泄漏
- 接口返回文件后立即移除缓存条目,减少内存占用
内容的提问来源于stack exchange,提问作者Edgar Gomez
相关产品推荐
相关产品推荐

