我可以不通过内存直接从HttpResponseMessage流传输到文件吗? [英] Can I directly stream from HttpResponseMessage to file without going through memory?

查看:403
本文介绍了我可以不通过内存直接从HttpResponseMessage流传输到文件吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序使用HttpClient将GET请求发送到Web API,这将返回一个文件.

My program uses HttpClient to send a GET request to a Web API, and this returns a file.

我现在使用以下代码(简化)将文件存储到光盘:

I now use this code (simplified) to store the file to disc:

public async Task<bool> DownloadFile()
{
    var client = new HttpClient();
    var uri = new Uri("http://somedomain.com/path");
    var response = await client.GetAsync(uri);

    if (response.IsSuccessStatusCode)
    {
        var fileName = response.Content.Headers.ContentDisposition.FileName;
        using (var fs = new FileStream("C:\test\" + fileName, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            await response.Content.CopyToAsync(fs);
            return true;
        }
    }

    return false;
}

现在,运行此代码时,该过程会将所有文件加载到内存中.我实际上希望流从HttpResponseMessage.Content流传输到FileStream,以便仅将一小部分保留在内存中.

Now, when this code runs, the process loads all of the file into memory. I actually would rather expect the stream gets streamed from the HttpResponseMessage.Content to the FileStream, so that only a small portion of it is held in memory.

我们计划在大文件(> 1GB)上使用它,那么有没有一种方法可以在不将所有文件都存储在内存中的情况下实现呢?

We are planning to use that on large files (> 1GB), so is there a way to achieve that without having all of the file in memory?

理想情况下,无需手动循环读取一部分到byte []并将该部分写入文件流,直到写入所有内容?

Ideally without manually looping through reading a portion to a byte[] and writing that portion to the file stream until all of the content is written?

推荐答案

这似乎是设计使然-如果您查看HttpClient.GetAsync()的文档,您会看到它说:

It looks like this is by-design - if you check the documentation for HttpClient.GetAsync() you'll see it says:

返回的任务对象将在整个响应后完成 (包括内容)已被读取

The returned task object will complete after the whole response (including content) is read

您可以改为使用HttpClient.GetStreamAsync()专门指出:

You can instead use HttpClient.GetStreamAsync() which specifically states:

此方法不会缓冲流.

This method does not buffer the stream.

无论如何,不要,然后据我所知,可以访问响应中的标头.由于这大概是一个要求(因为您是从标题中获取文件名的),因此您可能想使用HttpWebRequest代替,它使您可以获取响应详细信息(标题等),而无需将整个响应读入内存.像这样:

However you don't then get access to the headers in the response as far as I can see. Since that's presumably a requirement (as you're getting the file name from the headers), then you may want to use HttpWebRequest instead which allows you you to get the response details (headers etc.) without reading the whole response into memory. Something like:

public async Task<bool> DownloadFile()
{
    var uri = new Uri("http://somedomain.com/path");
    var request = WebRequest.CreateHttp(uri);
    var response = await request.GetResponseAsync();

    ContentDispositionHeaderValue contentDisposition;
    var fileName = ContentDispositionHeaderValue.TryParse(response.Headers["Content-Disposition"], out contentDisposition)
        ? contentDisposition.FileName
        : "noname.dat";
    using (var fs = new FileStream(@"C:\test\" + fileName, FileMode.Create, FileAccess.Write, FileShare.None))
    {
        await response.GetResponseStream().CopyToAsync(fs);
    }

    return true
}

请注意,如果请求返回的响应代码失败,则会引发异常,因此,如您的原始示例一样,在这种情况下,您可能希望将try..catch换行并返回false.

Note that if the request returns an unsuccessful response code an exception will be thrown, so you may wish to wrap in a try..catch and return false in this case as in your original example.

这篇关于我可以不通过内存直接从HttpResponseMessage流传输到文件吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆