使用C#代码下载文件后,Doc/Docx文件损坏且丢失原名问题排查
问题描述
我使用以下代码下载文件:
using (FileStream fileStream = File.OpenRead(filePath)) { MemoryStream memStream = new MemoryStream(); memStream.SetLength(fileStream.Length); fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length); Response.Clear(); Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; Response.AddHeader("Content-Disposition", "attachment; filename=" + item.filename); Response.BinaryWrite(memStream.ToArray()); Response.TransmitFile(filePath); Response.Flush(); Response.Close(); Response.End(); }
该代码整体运行正常,但下载后的Docx文件打开时会丢失原名,且提示“文件已损坏无法打开”。此问题仅出现在Doc和Docx文件上,Xlsx、Jpg、Pdf等格式均能正常使用。请问这与我的代码有关还是其他原因?
问题分析与解决方案
你的问题完全由代码逻辑错误导致,核心问题有三个:
- 重复输出文件内容:同时调用
Response.BinaryWrite(memStream.ToArray())和Response.TransmitFile(filePath)会将文件内容连续输出两次。Office文档(Doc/Docx属于结构化压缩包)对完整性要求极高,重复内容直接破坏文件结构,引发损坏提示;而图片、PDF等格式对冗余内容容错性更强,所以未出现明显问题。 - ContentType不匹配:代码硬编码了Docx的ContentType,但Doc格式文件需要使用
application/msword,类型不匹配会导致浏览器解析异常,影响文件名识别。 - 文件名未编码:直接拼接
filename=会导致特殊字符在部分浏览器中乱码或丢失,进而出现“丢失原名”的情况。
修正后的代码
using (FileStream fileStream = File.OpenRead(filePath)) { Response.Clear(); // 根据文件扩展名设置对应ContentType var fileExt = Path.GetExtension(filePath).ToLowerInvariant(); switch (fileExt) { case ".docx": Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; break; case ".doc": Response.ContentType = "application/msword"; break; case ".xlsx": Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; break; case ".pdf": Response.ContentType = "application/pdf"; break; default: Response.ContentType = "application/octet-stream"; break; } // 对文件名编码,避免特殊字符引发的识别问题 var encodedFileName = Uri.EscapeDataString(item.filename); Response.AddHeader("Content-Disposition", $"attachment; filename=\"{encodedFileName}\""); // 二选一输出文件即可,TransmitFile更高效,无需内存流中转 Response.TransmitFile(filePath); // 若需处理流,可替换为:fileStream.CopyTo(Response.OutputStream); Response.Flush(); Response.End(); }
额外优化提示
- 无需使用
MemoryStream中转文件,直接输出可减少内存占用 - 不要调用
Response.Close(),Response.End()已终止响应流程 - 确保
item.filename包含正确的文件扩展名,否则浏览器无法识别文件类型
内容的提问来源于stack exchange,提问作者Naima BEN MOUH
相关产品推荐
相关产品推荐

