本文介绍了使用HttpClient的异步文件下载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有它返回一个CSV文件POST请求的服务。我想使用异步技术来下载文件说。虽然我可以得到的文件,我的code有几个突出的问题和疑问:

1)这是真的异步?

2)是否有办法知道内容的长度,即使它在分块格式发送?想想进度条)。

3)如何可以为了抵挡程序退出,直到所有工作完成最好的我监测进展情况。

 使用系统;
使用System.IO;
使用System.Net.Http;命名空间TestHttpClient2
{
    类节目
    {
        / *
         *使用雅虎门户网站访问报价的股票 - 执行异步操作。
         * /        静态字符串的baseUrl =htt​​p://real-chart.finance.yahoo.com/;
        静态字符串requestUrlFormat =/table.csv?s={0}&d=0&e=9&f=2015&g=d&a=4&b=5&c=2000&ignore=.csv ;        静态无效的主要(字串[] args)
        {
            而(真)
            {
                Console.Write(输入一个符号来研究或[Enter]键退出:);
                串符号=到Console.ReadLine();
                如果(string.IsNullOrEmpty(符号))
                    打破;
                DownloadDataForStockAsync(符号);
            }
        }        静态异步无效DownloadDataForStockAsync(串符号)
        {
            尝试
            {
                使用(VAR的客户=新的HttpClient())
                {
                    client.BaseAddress =新的URI(的baseUrl);
                    client.Timeout = TimeSpan.FromMinutes(5);
                    字符串requestUrl =的String.Format(requestUrlFormat,符号);                    // VAR内容=新KeyValuePair<字符串,字符串> [] {
                    //};
                    //变种formUrlEn codedContent =新FormUrlEn codedContent(内容);                    VAR要求=新的Htt prequestMessage(HttpMethod.Post,requestUrl);
                    VAR sendTask = client.SendAsync(请求,HttpCompletionOption.ResponseHeadersRead);
                    VAR响应= sendTask.Result.EnsureSuccessStatus code();
                    VAR httpStream =等待response.Content.ReadAsStreamAsync();                    字符串输出目录=StockQuotes;                    如果(!Directory.Exists(输出目录))
                    {
                        Directory.CreateDirectory(输出目录);
                    }                    日期时间currentDateTime = DateTime.Now;
                    VAR文件路径= Path.Combine(输出目录,的String.Format({1:D4} _ {2} D2 _ {3} D2 _ {4} D2 _ {5} D2 _ {6:D2} _ {7:D3} _ {0}的.csv
                        符号,
                        currentDateTime.Year,currentDateTime.Month,currentDateTime.Day,
                        currentDateTime.Hour,currentDateTime.Minute,currentDateTime.Second,currentDateTime.Millisecond
                        ));                    使用(VAR FILESTREAM = File.Create(文件路径))
                    使用(VAR读者=新的StreamReader(httpStream))
                    {
                        httpStream.CopyTo(FILESTREAM);
                        fileStream.Flush();
                    }
                }
            }
            赶上(异常前)
            {
                Console.WriteLine(错误,请重试!);
            }
        }    }
}


解决方案

Yes, mostly. The DownloadDataForStockAsync() method will return before the operation is complete, at the await response.Content.ReadAsStreamAsync() statement.

The main exception is near the end of the method, where you call Stream.CopyTo(). This isn't asynchronous, and because it's a potentially lengthy operation could result in noticeable delays. However, in a console program you won't notice, because the continuation of the method is executed in the thread pool rather than the original calling thread.

If you intend to move this code to a GUI framework, such as Winforms or WPF, you should change the statement to read await httpStream.CopyToAsync(fileStream);

Assuming the server includes the Content-Length in the headers (and it should), yes. This should be possible.

Note that if you were using HttpWebRequest, the response object would have a ContentLength property giving you this value directly. You are using HttpRequestMessage here instead, which I'm less familiar with. But as near as I can tell, you should be able to access the Content-Length value like this:

long? contentLength = response.Content.Headers.ContentLength;

if (contentLength != null)
{
    // use value to initialize "determinate" progress indication
}
else
{
    // no content-length provided; will need to display progress as "indeterminate"
}

There are lots of ways. I will point out that any reasonable way will require that you change the DownloadDataForStockAsync() method so that it returns Task and not void. Otherwise, you don't have access to the task that's created. You should do this anyway though, so that's not a big deal. :)

The simplest would be to just keep a list of all the tasks you start, and then wait on them before exiting:

static void Main(string[] args)
{
    List<Task> tasks = new List<Task>();

    while (true) 
    {
        Console.Write("Enter a symbol to research or [ENTER] to exit: ");
        string symbol = Console.ReadLine();
        if (string.IsNullOrEmpty(symbol))
            break;
        tasks.Add(DownloadDataForStockAsync(symbol));
    }

    Task.WaitAll(tasks);
}

Of course, this requires that you explicitly maintain a list of each Task object, including those which have already completed. If you intend for this to run for a long time and process a very large number of symbols, that might be prohibitive. In that case, you might prefer to use the CountDownEvent object:

static void Main(string[] args)
{
    CountDownEvent countDown = new CountDownEvent();

    while (true) 
    {
        Console.Write("Enter a symbol to research or [ENTER] to exit: ");
        string symbol = Console.ReadLine();
        if (string.IsNullOrEmpty(symbol))
            break;

        countDown.AddCount();
        DownloadDataForStockAsync(symbol).ContinueWith(task => countdown.Signal()) ;
    }

    countDown.Wait();
}

This simply increments the CountDownEvent counter for each task you create, and attaches a continuation to each task to decrement the counter. When the counter reaches zero, the event is set, allowing a call to Wait() to return.

这篇关于使用HttpClient的异步文件下载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 19:49