如何更改此代码以下载大于2GB的文件?

时间:2016-01-10 14:23:06

标签: c# download

我使用此代码适用于较小的文件,但无法下载文件大小超过2GB的文件。 我也试过使用webclient,但它不适合我的代码或不能正常工作,因为这段代码只是试图弄清楚如何用这个下载2GB文件。感谢

System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url_);
//request.Proxy = WebRequest.GetSystemWebProxy();
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
ServicePoint sp = request.ServicePoint;
sp.ConnectionLimit = MAX_THREADS;
response.Close();
// gets the size of the file in bytes
Int64 iSize = response.ContentLength;
// keeps track of the total bytes downloaded so we can update the progress bar
Int64 iRunningByteTotal = 0;
UpdateStatus("File OK", count);
// use the webclient object to download the file
using (System.Net.WebClient client = new System.Net.WebClient())
{
    // open the file at the remote URL for reading
    using (System.IO.Stream streamRemote = client.OpenRead(new Uri(VideoUrl)))
    {
        // using the FileStream object, we can write the downloaded bytes to the file system
        using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            // loop the stream and get the file into the byte buffer
            int iByteSize = 0;
            byte[] byteBuffer = new byte[iSize];<---------throws error here
            while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
            {
                if (isCanceled == true) return;
                if (manualResetEvent.WaitOne(0, false)) return;
                // write the bytes to the file system at the file path specified
                streamLocal.Write(byteBuffer, 0, iByteSize);
                iRunningByteTotal += iByteSize;

                // calculate the progress out of a base "100"
                double dIndex = (double)(iRunningByteTotal);
                double dTotal = (double)byteBuffer.Length;
                double dProgressPercentage = (dIndex / dTotal);
                int iProgressPercentage = (int)(dProgressPercentage * 100);
                UpdateProgress((int)iProgressPercentage, count);
            }

            // clean up the file stream
            streamLocal.Close();
        }
        // close the connection to the remote server
        streamRemote.Close();
    }
} 

error

例外:

System.OverflowException was caught
  HResult=-2146233066
  Message=Arithmetic operation resulted in an overflow.
  Source=Downloader
  StackTrace:
       at MetroFramework.Demo.frmMain.FileDownloader(Object state) in frmMain.cs:line 595--->byte[] byteBuffer = new byte[iSize];
  InnerException: 

2 个答案:

答案 0 :(得分:2)

乍一看,你似乎完成了所有事情:

  • 您已分配缓冲区
  • 您已经创建了一个填充缓冲区的循环
  • 然后将缓冲区刷新到文件,然后迭代下一个缓冲区
  • 您还包括了运行总计和进度更新

一切......保存一件事:

byte[] byteBuffer = new byte[iSize];

这会将缓冲区分配为要下载的文件的大小。换句话说,如果文件大小为1GiB,则分配1 GiB缓冲区,然后尝试在一次调用中填充整个缓冲区。这种填充可能返回更少的字节,但您仍然分配了整个缓冲区。请注意,.NET中单个数组的最大长度是32位数,这意味着即使您重新编译64位程序并且实际上有足够的可用内存,对于大于2GiB的文件,它仍然会失败。

这样做:

byte[] byteBuffer = new byte[65536];

使用64KiB缓冲区或其他一些合理的缓冲区大小。

答案 1 :(得分:2)

除了由@Lasse's answer修复的缓冲问题外,实际问题是您正在重新发明轮子。

使用WebClient.DownloadFile()并订阅DownloadProgressChanged事件:

using (System.Net.WebClient client = new System.Net.WebClient())
{
    client.DownloadProgressChanged += WebClient_DownloadProgressChanged;

    client.DownloadFile(sourceUrl, targetFile);

    client.DownloadProgressChanged -= WebClient_DownloadProgressChanged;
}

private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    // e.BytesReceived, 
    // e.TotalBytesToReceive,
}