【问题标题】:Delete file after returning it on an API request在 API 请求返回后删除文件
【发布时间】:2019-12-31 00:17:05
【问题描述】:

我收到一个请求,我使用该请求创建一个文件并将其返回给客户端。

文件发送后我希望将其删除。

由于我收到很多请求,文件很大,内存不足,我不想将它缓冲在内存中发送。

在内存中不缓冲整个文件的情况下,我可以使用的唯一方法是:

Response.TransmitFile(filepath)

问题在于它是异步执行的,所以如果我在调用之后删除它,文件下载就会中断。

我尝试调用 Flush,在 finally 块上添加删除,但这些都不起作用。想过继承HttpResponse来尝试修改TransmitFile,但它是一个密封类。我尝试使用 HttpResponse.ClientDisconnectedToken 但要么我不明白如何正确使用它,要么在这种情况下它不起作用。

我怎样才能做到这一点?有比调用 HttpResponse 的 TransmitFile 更好的方法吗?始终考虑到这是一个 API,不能将文件分解为不同的请求,并且 它不会将完整的文件加载到内存中

我不确定它是否有帮助,但我的控制器是从 AbpApiController 继承的。

【问题讨论】:

  • 我什至不知道可以在不先将数据放入内存的情况下将数据放到网络上,每天学习新东西!在异步调用上使用 await 关键字来暂停执行,直到方法返回
  • 我会在客户端请求文件时删除文件或将其放在计时器上。你永远不应该认为它成功了。
  • @tgralex 谢谢,但正如我所写,我尝试了 finally 块选项。不工作。它会在文件传输之前将其删除。另一个答案在内存中缓冲响应。
  • @ĴošħWilliard 好吧,它的措辞可以更好。如果它是一个 1GB 的文件,那么 RAM 使用量不会上升到任何明显的量。 TransmitFile 不是异步方法,不能等待。

标签: c# asp.net-mvc dispose abp


【解决方案1】:

TransmitFileWithLimit 的一个实现,它可以在很多方面进行改进,但它确实有效

HttpResponse 的扩展

public static class HttpResponseExtensions
{
    public static void TransmitFileWithLimit(this HttpResponse response, string path, int limit)
    {
        var buffer = new byte[limit];
        var offset = 0;
        response.ClearContent();
        response.Clear();
        response.ContentType = "text/plain";

        using (var fileStream = File.OpenRead(path))
        {
            var lengthStream = fileStream.Length;
            while (offset < lengthStream)
            {
                var lengthBytes = fileStream.Read(buffer, 0, limit);
                var chars = System.Text.Encoding.ASCII.GetString(buffer, 0, lengthBytes).ToCharArray();
                response.Write(chars, 0, lengthBytes);
                offset += lengthBytes;
            }
        }
        response.Flush();
        response.End();
    }
}

内部控制器

    public void Get()
    {
        var path = @"C:\temporal\bigfile.mp4";
        var response = HttpContext.Current.Response;
        response.ClearContent();
        response.Clear();
        response.AddHeader("Content-Disposition", "inline; filename=" + HttpUtility.UrlPathEncode(path));
        response.ContentType = "text/plain";
        response.AddHeader("Content-Length", new FileInfo(path).Length.ToString());
        response.Flush();
        HttpContext.Current.ApplicationInstance.CompleteRequest();

        TransmitFileWithLimit(path, 10000);
        File.Delete(path);
    }

【讨论】:

  • 谢谢
【解决方案2】:

您可以做的是从您的文件创建一个字节数组,然后删除该文件。 因此,一旦创建它,​​就将其存储在内存中,然后删除文件并返回字节数组。 检查this answer to see an example.

我希望这会有所帮助。

【讨论】:

  • 我会引用自己的话:“我不想在内存中缓冲它来发送它”
【解决方案3】:

您在临时文件夹中创建文件,只需创建一个作业以根据日期/时间删除所有文件。也许给用户 4 小时的时间来下载文件。

【讨论】:

  • 这是我想出的最好的办法,但我宁愿在不再需要该文件后不久删除该文件。知道速度慢的一些客户可能会拥有该过程,应该将所有文件保留 20 多个小时,这对他们中的大多数人来说是完全没有必要的。
  • 我也更喜欢这种方法,尤其是因为你不会浪费内存来将文件的全部内容加载到内存中。您始终可以安排一个每天运行一次的简单作业来删除和清理临时文件夹。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-16
  • 1970-01-01
  • 2014-11-20
  • 1970-01-01
  • 2022-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多