使用CsvHelper导出超2GB数据到Azure Blob Storage报Stream too long如何解决
问题原因
- 你当前的实现是先把整个CSV文件全部写入
MemoryStream内存流中,再一次性上传到Azure Blob Storage。MemoryStream本身存在2GB的容量上限,当生成的CSV超过这个阈值时就会触发「Stream was too long」报错。 - 该实现还会额外占用和文件大小对等的服务器内存,大文件场景下极易出现内存溢出、上传超时等额外问题。
解决方案
核心逻辑是跳过本地内存缓冲全量数据的步骤,直接向Azure Blob的可写流中写入CSV内容,边生成CSV边上传,完全规避内存流的容量限制,同时大幅降低内存占用。
修改后适配原有SDK的代码如下:
public static void EXPORT_CSV(DataTable dt, string fileName, ILogger log) { try { // 原有存储账号、容器、Blob引用逻辑保持不变 var cnStorage = Environment.GetEnvironmentVariable("cnStorage"); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(cnStorage); CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobClient.GetContainerReference("dataexport"); container.CreateIfNotExists(); CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName); // 可选:设置Blob的ContentType为csv格式 blockBlob.Properties.ContentType = "text/csv; charset=utf-8"; // 可选:设置单块上传大小,可根据网络环境调整,范围1MB~100MB blockBlob.StreamWriteSizeInBytes = 10 * 1024 * 1024; // 这里设为10MB log.LogInformation($"C# BatchDataExportCSVsegnalazioni START CSV生成上传 at: {DateTime.Now}"); // 直接打开Blob的可写流,不需要本地MemoryStream缓冲 using (var blobStream = blockBlob.OpenWrite()) using (var writer = new StreamWriter(blobStream, Encoding.UTF8)) using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csvWriter.Configuration.TypeConverterOptionsCache.GetOptions<DateTime>().Formats = new[] { "dd/MM/yyyy" }; // 写入表头 foreach (DataColumn column in dt.Columns) { csvWriter.WriteField(column.ColumnName); } csvWriter.NextRecord(); // 逐行写入数据,写完直接传到Blob,不需要全量存内存 foreach (DataRow row in dt.Rows) { for (var i = 0; i < dt.Columns.Count; i++) { csvWriter.WriteField(row[i]); } csvWriter.NextRecord(); } // 手动Flush确保所有数据都写入流 csvWriter.Flush(); writer.Flush(); } log.LogInformation($"C# BatchDataExportCSVsegnalazioni END 上传完成 at: {DateTime.Now}"); } catch (Exception ex) { log.LogError("Error upload BatchDataExportCSVsegnalazioni: " + ex.Message); throw; } }
额外优化建议
- 如果使用的是新版Azure Blob SDK
Azure.Storage.Blobs,可以将blockBlob.OpenWrite()替换为blockBlob.OpenWrite(true)方法,逻辑完全一致。 - 如果数据量特别大,可以对DataTable做分批查询读取,避免一次性把全量数据加载到DataTable中占内存,进一步提升性能。
- 可以配置断点续传逻辑,避免网络波动导致大文件上传失败需要重传。
内容的提问来源于stack exchange,提问作者mtallon
相关产品推荐
相关产品推荐

