Blazor InputFile组件大JSON文件上传解析异常求助
Blazor InputFile上传大JSON文件被截断的解决方法
问题描述
使用Blazor的InputFile组件上传并解析JSON文件时,上传11MB、约30万行的大文件会触发JSON内容无效异常。调试发现文件内容被截断,流在约100000索引位置后的元素值全部为0。
相关代码
razor
<InputFile @ref="InputFile" OnChange="OnUploadHandler" />
razor.cs
async Task OnUploadHandler(InputFileChangeEventArgs e) { var stream = e.File.OpenReadStream(Int32.MaxValue); Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length); Byte[] buffer = new Byte[length]; await stream.ReadAsync(buffer.AsMemory(0, length)); var content = Encoding.Default.GetString(buffer); var parsed = JObject.Parse(content); }
示例情况
上传示例文件lorem.json时,调试查看content变量,发现内容被截断至JSON元素中间,示例如下:
[ { "_id": "638dfa2f5e1dd23eb7b407e9", "index": 0, "guid": "89e63cb9-0498-4f5f-829e-9aaec0cf6855", "address": "706 Irving Avenue, Leroy, Iowa, 6592", "about": "Cupidatat adipisicing cupidatat culpa et labore id proident incididunt occaecat. Laboris velit fugiat consequat est sunt veniam ex. Ullamco irure ex laborum dolor esse anim et sunt in nulla ea aliquip. Ea proident irure cillum quis qui magna id ad ex qui. Veniam anim Lorem aliqua officia. Et cillum dolore ad aliqua ex voluptate culpa dolor occaecat cupidatat ex qui et enim. Elit irure voluptate non cupidatat aliqua duis in duis ut qui.\r\n", "tags": [ "irure", "tempor", "irure", "consectetur", "duis", "proident", "ex" ], "friends": [ { "id": 0, "name": "Zimmerman Burch" }, { "id": 1, "name": "Snow Harrington" } ], "greeting": "Hello, undefined! You have 3 unread messages.", "favoriteFruit": "strawberry" }, { "_id": "638dfa2f226b8c0be4f73fa9", "index": 1, "guid": "0a7b9bb4-580f-460e-b876-f0cf62260983",
问题原因
核心问题在于await stream.ReadAsync(buffer.AsMemory(0, length));这行代码:ReadAsync方法仅返回实际读取的字节数,它不会保证一次性读完整个流。对于大文件,系统会分批次读取,未被读取的buffer区域会保留默认值0,导致后续转字符串时出现截断的无效JSON。
另外,使用Encoding.Default也可能引发编码错误,JSON文件通常采用UTF-8编码,应该优先使用Encoding.UTF8。
解决方法
方法1:使用StreamReader读取完整内容
通过StreamReader的ReadToEndAsync方法自动循环读取流直到结束,确保获取完整文件内容:
async Task OnUploadHandler(InputFileChangeEventArgs e) { using var stream = e.File.OpenReadStream(Int32.MaxValue); using var reader = new StreamReader(stream, Encoding.UTF8); var content = await reader.ReadToEndAsync(); var parsed = JObject.Parse(content); // 后续处理逻辑 }
方法2:直接从流解析JSON(推荐,节省内存)
对于大文件,没必要将整个JSON字符串加载到内存中,直接使用JsonSerializer或JsonDocument从流解析,性能更优:
// 使用JsonSerializer解析为强类型对象 async Task OnUploadHandler(InputFileChangeEventArgs e) { using var stream = e.File.OpenReadStream(Int32.MaxValue); // 替换YourModelType为实际的模型类型 var data = await JsonSerializer.DeserializeAsync<List<YourModelType>>(stream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); // 后续处理逻辑 } // 使用JsonDocument解析(无需定义模型) async Task OnUploadHandler(InputFileChangeEventArgs e) { using var stream = e.File.OpenReadStream(Int32.MaxValue); using var doc = await JsonDocument.ParseAsync(stream); var root = doc.RootElement; // 遍历root处理JSON内容 }
方法3:循环读取流填充buffer
如果必须手动操作字节数组,需要循环调用ReadAsync直到流结束:
async Task OnUploadHandler(InputFileChangeEventArgs e) { using var stream = e.File.OpenReadStream(Int32.MaxValue); int totalBytesRead = 0; byte[] buffer = new byte[4096]; // 用小buffer分批读取,避免内存占用过大 using var memoryStream = new MemoryStream(); while ((totalBytesRead = await stream.ReadAsync(buffer)) > 0) { await memoryStream.WriteAsync(buffer.AsMemory(0, totalBytesRead)); } var content = Encoding.UTF8.GetString(memoryStream.ToArray()); var parsed = JObject.Parse(content); // 后续处理逻辑 }
内容的提问来源于stack exchange,提问作者Freshman's Dream
相关产品推荐
相关产品推荐

