Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用HttpClient进行异步文件下载_C#_Asynchronous_Download_Async Await_Dotnet Httpclient - Fatal编程技术网

C# 使用HttpClient进行异步文件下载

C# 使用HttpClient进行异步文件下载,c#,asynchronous,download,async-await,dotnet-httpclient,C#,Asynchronous,Download,Async Await,Dotnet Httpclient,我有一个将csv文件返回到POST请求的服务。我想使用异步技术下载上述文件。虽然我可以获得该文件,但我的代码有几个悬而未决的问题: 1) 这真的是异步的吗 2) 有没有办法知道内容的长度,即使它是以分块格式发送的?想想进度条) 3) 我如何才能最好地监控进度,以推迟程序退出,直到所有工作完成 using System; using System.IO; using System.Net.Http; namespace TestHttpClient2 { class Program

我有一个将csv文件返回到POST请求的服务。我想使用异步技术下载上述文件。虽然我可以获得该文件,但我的代码有几个悬而未决的问题:

1) 这真的是异步的吗

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

3) 我如何才能最好地监控进度,以推迟程序退出,直到所有工作完成

using System;
using System.IO;
using System.Net.Http;

namespace TestHttpClient2
{
    class Program
    {
        /*
         * Use Yahoo portal to access quotes for stocks - perform asynchronous operations.
         */

        static string baseUrl = "http://real-chart.finance.yahoo.com/";
        static string requestUrlFormat = "/table.csv?s={0}&d=0&e=9&f=2015&g=d&a=4&b=5&c=2000&ignore=.csv";

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

        static async void DownloadDataForStockAsync(string symbol)
        {
            try
            {
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(baseUrl);
                    client.Timeout = TimeSpan.FromMinutes(5);
                    string requestUrl = string.Format(requestUrlFormat, symbol);

                    //var content = new KeyValuePair<string, string>[] {
                    //    };
                    //var formUrlEncodedContent = new FormUrlEncodedContent(content);

                    var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
                    var sendTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
                    var response = sendTask.Result.EnsureSuccessStatusCode();
                    var httpStream = await response.Content.ReadAsStreamAsync();

                    string OutputDirectory = "StockQuotes";

                    if (!Directory.Exists(OutputDirectory))
                    {
                        Directory.CreateDirectory(OutputDirectory);
                    }

                    DateTime currentDateTime = DateTime.Now;
                    var filePath = Path.Combine(OutputDirectory, string.Format("{1:D4}_{2:D2}_{3:D2}_{4:D2}_{5:D2}_{6:D2}_{7:D3}_{0}.csv",
                        symbol,
                        currentDateTime.Year, currentDateTime.Month, currentDateTime.Day,
                        currentDateTime.Hour, currentDateTime.Minute, currentDateTime.Second, currentDateTime.Millisecond
                        ));

                    using (var fileStream = File.Create(filePath))
                    using (var reader = new StreamReader(httpStream))
                    {
                        httpStream.CopyTo(fileStream);
                        fileStream.Flush();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error, try again!");
            }
        }

    }
}
使用系统;
使用System.IO;
使用System.Net.Http;
命名空间TestHttpClient2
{
班级计划
{
/*
*使用雅虎门户访问股票报价-执行异步操作。
*/
静态字符串baseUrl=”http://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”;
静态void Main(字符串[]参数)
{
while(true)
{
控制台。写入(“输入一个符号进行研究或[输入]退出:”;
字符串符号=Console.ReadLine();
if(string.IsNullOrEmpty(符号))
打破
下载数据forstockasync(符号);
}
}
静态异步void下载DataForStockAsync(字符串符号)
{
尝试
{
使用(var client=new HttpClient())
{
client.BaseAddress=新Uri(baseUrl);
client.Timeout=TimeSpan.frommins(5);
string requestUrl=string.Format(requestUrlFormat,符号);
//var内容=新的KeyValuePair[]{
//    };
//var formUrlEncodedContent=新的formUrlEncodedContent(content);
var request=newhttprequestmessage(HttpMethod.Post,requestUrl);
var sendTask=client.sendsync(请求,HttpCompletionOption.ResponseHeadersRead);
var response=sendTask.Result.EnsureSuccessStatusCode();
var httpStream=await response.Content.ReadAsStreamAsync();
字符串OutputDirectory=“StockQuotes”;
如果(!Directory.Exists(OutputDirectory))
{
CreateDirectory(OutputDirectory);
}
DateTime currentDateTime=DateTime.Now;
var filePath=Path.Combine(OutputDirectory,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.毫秒
));
使用(var fileStream=File.Create(filePath))
使用(var reader=newstreamreader(httpStream))
{
httpStream.CopyTo(fileStream);
Flush();
}
}
}
捕获(例外情况除外)
{
WriteLine(“错误,再试一次!”);
}
}
}
}
  • “这真的是异步的吗?”
  • 是的,大部分是这样。
    DownloadDataForStockAsync()
    方法将在操作完成之前,在
    wait response.Content.ReadAsStreamAsync()
    语句中返回

    主要的异常在方法末尾附近,在这里调用
    Stream.CopyTo()
    。这不是异步的,因为这是一个潜在的长时间操作,可能会导致明显的延迟。但是,在控制台程序中,您不会注意到,因为方法的延续是在线程池中执行的,而不是在原始调用线程中执行的

    如果要将此代码移动到GUI框架,如Winforms或WPF,则应将语句更改为读取
    await httpStream.CopyToAsync(fileStream)

  • 有没有办法知道内容的长度,即使它是以分块格式发送的?想想进度条)
  • 假设服务器在标题中包含
    内容长度
    (应该是这样),则是。这应该是可能的

    请注意,如果您使用的是
    HttpWebRequest
    ,则响应对象将有一个
    ContentLength
    属性直接提供此值。您在这里使用的是我不太熟悉的
    HttpRequestMessage
    。但就我所知,您应该能够访问
    Content Length
    值,如下所示:

    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"
    }
    
  • 我如何才能最好地监控进度,以推迟程序退出,直到所有工作完成
  • 有很多方法。我要指出,任何合理的方法都需要更改
    DownloadDataForStockAsync()
    方法,使其返回
    Task
    ,而不是
    void
    。否则,您将无法访问所创建的任务。无论如何,你都应该这样做,所以这没什么大不了的。:)

    最简单的方法是保留一份您启动的所有任务的列表,然后在退出之前等待它们:

    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);
    }
    

    这只是为您创建的每个任务增加
    CountDownEvent
    计数器,并为每个任务附加一个continuation以减少计数器。当计数器达到零时,将设置事件,允许对
    Wait()
    的调用返回。

    根据您的异步问题,请查看
    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();
    }