【问题标题】:How to delete file after download with ASP.NET MVC?使用 ASP.NET MVC 下载后如何删除文件?
【发布时间】:2011-01-03 17:52:45
【问题描述】:

我想在下载后立即删除文件,我该怎么做?我尝试继承 FilePathResult 并覆盖 WriteFile 方法,在该方法中我删除文件后

HttpResponseBase.TransmitFile

被调用,但这会挂起应用程序。

我可以在用户下载文件后安全地删除它吗?

【问题讨论】:

  • 解决方案应该出现在“答案”中,而不是问题中。

标签: c# asp.net-mvc


【解决方案1】:

您可以只返回以FileOptions.DeleteOnClose 打开的普通FileStreamResult。文件流将由 asp.net 与结果一起处理。这个答案不需要使用在某些情况下可能适得其反的低级响应方法。也不会做额外的工作,比如将文件整体加载到内存中。

var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
return File(
    fileStream: fs,
    contentType: System.Net.Mime.MediaTypeNames.Application.Octet,
    fileDownloadName: "File.abc");

此答案基于 Alan West 的回答和 Thariq Nugrohotomo 的评论。

【讨论】:

  • 这对我来说非常有效。在我看来,迄今为止最简单的解决方案。
  • 我强烈推荐这个答案。 (请记住也支持 Thariq Nugrohotomo 对此答案的评论:stackoverflow.com/a/14763098/170309
  • 这个答案对我来说效果最好,因为我无法将文件加载到内存中,因为它的大小并且不需要额外的操作属性或委托。
  • 绝对应该是公认的答案。
【解决方案2】:

读取文件的字节,删除它,调用基本控制器的文件操作。

public class MyBaseController : Controller
{
    protected FileContentResult TemporaryFile(string fileName, string contentType, string fileDownloadName)
    {
        var bytes = System.IO.File.ReadAllBytes(fileName);
        System.IO.File.Delete(fileName);
        return File(bytes, contentType, fileDownloadName);
    }
}

顺便说一句,如果您正在处理非常大的文件,并且您担心内存消耗,则可以避免使用此方法。

【讨论】:

  • 您确定这是此问题的有效答案吗?
  • +1 我比公认的答案更喜欢这个。不需要属性或请求刷新,代码很明显:将文件字节读入内存,删除物理文件并将字节从内存返回给用户。谢谢!
  • 此解决方案无法扩展,适用于大文件或大量用户。随着用户和/或文件大小的增长,内存消耗将呈指数增长。
  • 为了更好的扩展性,你可以切换到FileStreamResult,流本身应该用FileOptions.DeleteOnClose打开。这样,在您传递流并且 ASP 处理完流之后,流将被关闭并自动删除文件。 (系统崩溃除外)
【解决方案3】:

创建文件并保存。

Response.Flush() 将所有数据发送给客户端。

然后你就可以删除临时文件了。

这对我有用:

FileInfo newFile = new FileInfo(Server.MapPath(tmpFile));

//create file, and save it
//...

string attachment = string.Format("attachment; filename={0}", fileName);
Response.Clear();
Response.AddHeader("content-disposition", attachment);
Response.ContentType = fileType;
Response.WriteFile(newFile.FullName);
Response.Flush();
newFile.Delete();
Response.End();

【讨论】:

  • 它是否也适用于大文件(大于 512 Mb)?
【解决方案4】:

以上答案对我有帮助,这就是我最终得到的结果:

public class DeleteFileAttribute : ActionFilterAttribute
{
  public override void OnResultExecuted(ResultExecutedContext filterContext)
  {
     filterContext.HttpContext.Response.Flush();
     var filePathResult = filterContext.Result as FilePathResult;
     if (filePathResult != null)
     {
        System.IO.File.Delete(filePathResult.FileName);
     }
  }
}

【讨论】:

    【解决方案5】:

    您可以使用 OnActionExecuted 方法为操作创建自定义操作过滤器,然后在操作完成后删除文件,类似于

    public class DeleteFileAttribute : ActionFilterAttribute 
    { 
        public override void OnActionExecuted(ActionExecutedContext filterContext) 
        { 
            // Delete file 
        } 
    } 
    

    那么你的动作有

    [DeleteFileAttribute]
    public FileContentResult GetFile(int id)
    {
       ...
    }
    

    【讨论】:

    • 下载挂起并且永远不会完成,想法?
    • 当然,我没想到,您是在下载完成之前删除文件。您能否在每次请求新结果之前删除先前生成的文件,这就是我在类似的情况下所做的。
    • 它增加了不必要的复杂性,我应该将下载的文件存储在数据库中,因为没有办法让后续文件知道 previos 文件。
    • 这个想法是可行的,但是除非按照下面 Trax72 的回答中提到的那样刷新响应,否则它不起作用。
    • 对我来说:onActionExecuteddid 无法正常工作 - 但 'OnResultExecuted' 有效(请参阅下面的替代答案)。
    【解决方案6】:

    我在 WebAPI 中执行了相同的操作。我需要在下载表单服务器后删除文件。 我们可以创建自定义响应消息类。以文件路径为参数,传输后删除。

     public class FileHttpResponseMessage : HttpResponseMessage
        {
            private readonly string filePath;
    
            public FileHttpResponseMessage(string filePath)
            {
                this.filePath = filePath;
            }
    
            protected override void Dispose(bool disposing)
            {
                base.Dispose(disposing);
                File.Delete(filePath);
            }
        }
    

    在下面的代码中使用这个类,一旦它被写入响应流,它将删除你的文件。

    var response = new FileHttpResponseMessage(filePath);
                response.StatusCode = HttpStatusCode.OK;
                response.Content = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
                response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
                {
                    FileName = "MyReport.pdf"
                };
                return response;
    

    【讨论】:

    • 不需要调用Content.Dispose() - 它是在base.Dispose(diposing)调用中调用的。
    【解决方案7】:

    重写 OnResultExecuted 方法可能是正确的解决方案。该方法在响应写入后运行。

    public class DeleteFileAttribute : ActionFilterAttribute 
    { 
        public override void OnResultExecuted(ResultExecutedContext filterContext) 
        { 
            filterContext.HttpContext.Response.Flush();
            // Delete file 
        } 
    } 
    

    动作代码:

    [DeleteFileAttribute]
    public FileContentResult GetFile(int id)
    {
       //your action code
    }
    

    【讨论】:

      【解决方案8】:

      这里是基于@biesiad 为 ASP.NET MVC (https://stackoverflow.com/a/4488411/1726296) 提供的优雅解决方案的更新答案

      基本上它在响应发送后返回 EmptyResult。

      public ActionResult GetFile()
      {
          string theFilename = "<Full path your file name>"; //Your actual file name
              Response.Clear();
              Response.AddHeader("content-disposition", "attachment; filename=<file name to be shown as download>"); //optional if you want forced download
              Response.ContentType = "application/octet-stream"; //Appropriate content type based of file type
              Response.WriteFile(theFilename); //Write file to response
              Response.Flush(); //Flush contents
              Response.End(); //Complete the response
              System.IO.File.Delete(theFilename); //Delete your local file
      
              return new EmptyResult(); //return empty action result
      }
      

      【讨论】:

      • 我使用了这个解决方案,但是我需要在 response.end 之前删除文件,因为之后无法访问
      【解决方案9】:

      试试这个。这将正常工作。

      public class DeleteFileAttribute : ActionFilterAttribute
      {
        public override void OnResultExecuted( ResultExecutedContext filterContext )
        {
          filterContext.HttpContext.Response.Flush();
          string filePath = ( filterContext.Result as FilePathResult ).FileName;
          File.Delete( filePath );
        }
      }
      

      【讨论】:

        【解决方案10】:

        我用过的图案。

        1)创建文件。

        2)删除旧创建的文件,FileInfo.CreationTime

        3)用户下载。

        这个想法怎么样?

        【讨论】:

          【解决方案11】:

          解决方案:

          应该继承 FileResult 或创建自定义操作过滤器,但棘手的部分是在尝试删除文件之前刷新响应。

          【讨论】:

            【解决方案12】:

            我更喜欢返回HttpResponseMessage 的解决方案。我喜欢 Risord 的简单回答,所以我以同样的方式创建了一个流。然后,我没有返回File,而是将HttpResponseMessage.Content 属性设置为StreamContent 对象。

            var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
            return new HttpResponseMessage()
            {
                Content = new StreamContent(fs)
            };
            

            【讨论】:

              【解决方案13】:

              我已经在https://stackoverflow.com/a/43561635/1726296发布了这个解决方案

              public ActionResult GetFile()
                  {
                          string theFilename = "<Full path your file name>"; //Your actual file name
                          Response.Clear();
                          Response.AddHeader("content-disposition", "attachment; filename=<file name to be shown as download>"); //optional if you want forced download
                          Response.ContentType = "application/octet-stream"; //Appropriate content type based of file type
                          Response.WriteFile(theFilename); //Write file to response
                          Response.Flush(); //Flush contents
                          Response.End(); //Complete the response
                          System.IO.File.Delete(theFilename); //Delete your local file
              
                          return new EmptyResult(); //return empty action result
                  }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-03-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多