循环追加MemoryStream生成CSV文件下载无数据问题排查
解决MemoryStream循环追加数据后下载为空的问题
我一眼就瞅出问题所在了——你第一种写法里,循环往MemoryStream写完所有数据后,流的读取指针停在了末尾,当你把这个流交给StreamContent的时候,它从当前位置开始读,自然读不到任何内容!
先给你看修正后的正确代码:
var stream = new System.IO.MemoryStream(); for (int i = 1; i <= pageCount; i++) { search = GetSearch(searchResultParam); csvContent = GetCsvForSearchResult(search); byte[] data = System.Text.Encoding.UTF8.GetBytes(csvContent); stream.Write(data, 0, data.Length); } // 关键:把流的位置重置到起始点! stream.Position = 0; // 或者用 stream.Seek(0, System.IO.SeekOrigin.Begin); string fileName = "Review" + "-" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + ".csv"; var result = new System.Net.Http.HttpResponseMessage(HttpStatusCode.OK) { Content = new System.Net.Http.StreamContent(stream) }; result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); result.Content.Headers.ContentDisposition.FileName = fileName; result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/csv"); // 这里建议用text/csv更标准 // 可以不用手动设置ContentLength,StreamContent会自动处理 // result.Content.Headers.ContentLength = stream.Length;
为什么之前的写法会失败?
每次调用stream.Write()时,流的Position属性会自动往后移动,等写完所有数据后,Position就等于流的总长度(也就是末尾位置)。这时候用StreamContent读取流,会从当前Position开始,自然读不到任何字节,所以下载的文件是空的。
为什么第二种写法能看到数据但其实不对?
第二种写法里,你每次循环都新建一个MemoryStream,新创建的流默认Position是0,所以StreamContent能读到数据,但这里有个致命问题:每次循环都会覆盖之前的stream变量,最终只有最后一页的CSV数据被保留,前面所有页的数据都直接丢失了,这肯定不是你想要的批量导出效果。
额外小建议
- 把ContentType改成
text/csv比application/octet-stream更标准,浏览器能更好识别这是CSV文件 - 不需要手动设置
ContentLength,StreamContent会自动计算并设置这个响应头 - 如果CSV包含中文等非ASCII字符,建议在循环写入之前先写入UTF8 BOM,避免乱码:
// 在循环写入前添加UTF8 BOM byte[] bom = System.Text.Encoding.UTF8.GetPreamble(); stream.Write(bom, 0, bom.Length);
内容的提问来源于stack exchange,提问作者Nirusma
相关产品推荐
相关产品推荐

