You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 02:50:30