C#中使用CopyTo()后原始流丢失,Azure Blob文件损坏求助
问题分析与解决方案
核心问题
你遇到的文件损坏问题,根源在于用字符串中转二进制流的处理方式:
StreamReader是为纯文本设计的,读取二进制文件(如图片、PDF、Office文档)时,会因编码转换丢失原始字节数据。writer.WriteLine(fileContent)会在内容末尾额外添加换行符,篡改了原始文件的内容结构。- 原代码中
FileStream未用using包裹,可能导致文件写入不完整或资源泄漏。
推荐解决方案(兼容所有文件类型)
直接操作流的字节数据,避免字符串中转,通过MemoryStream备份源流,分别完成本地写入和Blob上传:
var stream = await this.DownloadFromSPO(pipeline).ConfigureAwait(false); if (stream == null) { return false; } // 备份源流到MemoryStream,避免操作后位置偏移 using var backupStream = new MemoryStream(); await stream.CopyToAsync(backupStream).ConfigureAwait(false); // 重置两个流的读取位置到起始点 stream.Position = 0; backupStream.Position = 0; // 保存到本地文件夹(使用using确保流正确释放) string filePath2 = Path.Combine("C:\\localLocation", pipeline.Name); using var outputFileStream = new FileStream(filePath2, FileMode.Create); await backupStream.CopyToAsync(outputFileStream).ConfigureAwait(false); // 上传到Azure Blob(重置源流位置后直接使用) CloudBlob blob = null; await AzureRetryHelper.OperationWithBasicRetryAsync(async () => { stream.Position = 0; blob = await this.blobHelper.UploadFileToBlob( stream, this.config.GetConfigValue(Constants.DataContainerName), pipeline.BlobNativeFilePath, true, pipeline.MimeType).ConfigureAwait(false); }).ConfigureAwait(false);
仅适用于纯文本文件的备选方案
如果你确认所有处理的都是纯文本文件,可以调整字符串中转逻辑,避免篡改内容:
1. 修改GetStream方法
public static Stream GetStream(string fileContent, Encoding encoding) { MemoryStream ms = new MemoryStream(); // 保持编码一致,且leaveOpen设为true避免提前关闭MemoryStream using StreamWriter writer = new StreamWriter(ms, encoding, leaveOpen: true); writer.Write(fileContent); // 用Write替代WriteLine,避免添加额外换行 writer.Flush(); ms.Seek(0, SeekOrigin.Begin); return ms; }
2. 调整主逻辑代码
var stream = await this.DownloadFromSPO(pipeline).ConfigureAwait(false); if (stream == null) { return false; } string filePath2 = Path.Combine("C:\\localLocation", pipeline.Name); string content = string.Empty; // 指定与原始文件一致的编码(如UTF8、GB2312等) using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { content = reader.ReadToEnd(); // 直接写入文本内容,避免编码错误 using var outputFileStream = new FileStream(filePath2, FileMode.Create); using var fileWriter = new StreamWriter(outputFileStream, Encoding.UTF8); fileWriter.Write(content); } // 用一致的编码重建流 stream = helper.GetStream(content, Encoding.UTF8); // 上传到Azure Blob CloudBlob blob = null; await AzureRetryHelper.OperationWithBasicRetryAsync(async () => { blob = await this.blobHelper.UploadFileToBlob( stream, this.config.GetConfigValue(Constants.DataContainerName), pipeline.BlobNativeFilePath, true, pipeline.MimeType).ConfigureAwait(false); }).ConfigureAwait(false);
关键注意事项
- 处理非文本文件时,禁止用字符串中转流,必须直接操作字节数据。
- 所有流对象务必用
using包裹,确保资源正确释放。 - 每次读取流前,必须重置
Position = 0,否则会从流的末尾开始读取,导致空数据。
内容的提问来源于stack exchange,提问作者Neelam
相关产品推荐
相关产品推荐

