代码之家  ›  专栏  ›  技术社区  ›  Cheetah

在C#中,从Internet下载文件并动态写入的正确方法是什么?

  •  1
  • Cheetah  · 技术社区  · 16 年前

    这是在Compact框架中完成的,我没有访问WebClient的权限,因此必须使用HttpWebRequests完成。

    我正在创建一个下载管理器应用程序,该应用程序将能够同时进行下载(一次不止一次下载),并且能够报告完成的百分比并恢复下载。

    这意味着我正在将一些字节下载到缓冲区中,然后将缓冲区写入磁盘。我只是想看看推荐的算法/程序是什么。

    这是我到目前为止主要的下载方法:

        private void StartDownload()
        {
            HttpWebRequest webReq = null;
            HttpWebResponse webRes = null;
            Stream fileBytes = null;
            FileStream saveStream = null;
    
            try
            {
                webReq = (HttpWebRequest)HttpWebRequest.Create(_url);
                webReq.Headers.Add(HttpRequestHeader.Cookie, "somedata");
                webRes = (HttpWebResponse)webReq.GetResponse();
    
                byte[] buffer = new byte[4096];
                long bytesRead = 0;
                long contentLength = webRes.ContentLength;
    
                if (File.Exists(_filePath))
                {
                    bytesRead = new FileInfo(_filePath).Length;
                }
    
                fileBytes = webRes.GetResponseStream();
                fileBytes.Seek(bytesRead, SeekOrigin.Begin);
    
                saveStream = new FileStream(_filePath, FileMode.Append, FileAccess.Write);
    
                while (bytesRead < contentLength)
                {
                    int read = fileBytes.Read(buffer, 0, 4096);
                    saveStream.Write(buffer, 0, read);
                    bytesRead += read;
                }
                //set download status to complete
                //_parent
            }
            catch
            {
                if (Thread.CurrentThread.ThreadState != ThreadState.AbortRequested)
                {
                   //Set status to error.
                }
            }
            finally
            {
                saveStream.Close();
                fileBytes.Close();
                webRes.Close();
                saveStream.Dispose();
                fileBytes.Dispose();
                saveStream = null;
                fileBytes = null;
                webRes = null;
                webReq = null;
            }
        }
    

    我应该下载一个更大的缓冲区吗?我是否应该经常(每4KB?)将缓冲区写入文件?是否应该有一些线程在其中休眠以确保没有使用所有CPU?我认为每4KB报告一次进度更改是愚蠢的,所以我计划每下载64KB报告一次进度更改。

    寻找一些一般的提示或任何我的代码到目前为止有问题的地方。

    5 回复  |  直到 16 年前
        1
  •  2
  •   ChrisLively    16 年前

    首先,我要去掉finally子句并将代码改为使用“ USING “条款。

    任何实现IDisposable的东西都应该以这种方式进行编程,以确保垃圾收集正确地进行,并且在应该的时候进行。

    例如:

    using (HttpWebRequest webReq = (HttpWebRequest)HttpWebRequest.Create(_url)) {
        /* more code here... */
    }
    

    其次,我不会用空值(alapascal风格)在头部实例化变量。见上面的例子。

    第三,下载应该在它自己的线程中,该线程与主线程中的回调函数同步,以报告状态。将同步调用放在while循环的中间。

        2
  •  2
  •   SLaks    16 年前

    WebClient DownloadFile 方法,如下所示:

    using(var wc = new WebClient()) {
        wc.DownloadFile(url, filePath);
    }
    

    :要报告下载进度,请致电 DownloadFileAsync DownloadProgressChanged 事件您也可以通过调用 CancelAsync

        3
  •  1
  •   Ed Altorfer    16 年前

    从用户体验的角度来看,您应该能够通过查看诸如Internet Explorer或Firefox之类的应用程序来回答这些问题。例如

    1. 在Internet Explorer中,新数据每几千字节报告一次,最高可达一兆字节。之后,它将以100KB的增量报告。
    2. 您的应用程序显然不应该占用100%的CPU,因为这在编程界不是一个好的礼仪。让你的线程至少有足够长的睡眠时间,而不是主宰CPU。

    WebClient 在.NET中学习,但是如果这是一个学习练习,那么你的方法是正确的。

    祝你好运你在正确的轨道上。

        4
  •  0
  •   David    16 年前

    您可以从已经发布并免费提供的现有代码中获得所需的所有提示。

    http://www.codeproject.com/KB/IP/MyDownloader.aspx

    更好的是,使用现有代码并根据您的需要进行修改(这就是为什么代码首先会发布在那里。)

        5
  •  0
  •   Thomas Levesque    16 年前

    如果需要跟踪进度,请使用 WebClient.DownloadFileAsync 随着 DownloadProgressChanged DownloadFileCompleted 事件

    WebClient wc = new WebClient();
    wc.DownloadProgressChanged += wc_DownloadProgressChanged;
    wc.DownloadFileCompleted += wc_DownloadFileCompleted;
    wc.DownloadFileAsync(sourceUri, localPath);
    
    ...
    
    private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        ...
    }
    
    private void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
        ...
    }