65.9K
CodeProject 正在变化。 阅读更多。
Home

在 .NET 中下载文件,包含所有信息:进度条、下载速度、支持取消和恢复

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (39投票s)

2007年3月11日

CPOL

2分钟阅读

viewsIcon

430373

downloadIcon

29655

如何在 .NET 中下载文件,并显示所有进度信息(进度条、下载速度),支持取消和恢复

Screenshot - screen.jpg

介绍  

我将解释如何使用 .NET Framework 构建一个完整、可靠和强大的下载管理器。
它能够显示下载过程中的各种数据,包括下载速度、文件大小、已下载大小和完成百分比。

已经基于此代码编写了一个全新的类,它具有逻辑/布局抽象、多文件下载支持,并且通过提供各种属性和事件而更易于使用。查看FileDownloader 文章

文件通过 HttpWebRequestHttpWebResponse 下载,并使用 StreamWriter 写入文件。所有这些都在单独的线程(使用 BackgroundWorker)中完成,因此使用此下载器的应用程序不会冻结。

使用代码 

演示应用程序非常简单,仅包含下载文件所需的 UI 组件。您当然可以在自己的应用程序中实现此下载器,或者只是使用它在后台下载,而无需任何用户交互。

最重要的代码可以在 BackgroundWorkerDoWork 方法中找到。首先,会尝试建立与文件的连接。如果成功,Do 循环中的脚本将开始逐块下载文件,直到没有剩余字节要下载。请注意,一旦收到一个数据块,它就会被写入本地目标文件。

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
    ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

        'Creating the request and getting the response
        Dim theResponse As HttpWebResponse
        Dim theRequest As HttpWebRequest
        Try 'Checks if the file exist

            theRequest = WebRequest.Create(Me.txtFileName.Text)
            theResponse = theRequest.GetResponse
        Catch ex As Exception

            MessageBox.Show("An error occurred while downloading file. _
			Possible causes:" & ControlChars.CrLf & _
                            "1) File doesn't exist" & ControlChars.CrLf & _
                            "2) Remote server error", "Error", _
			MessageBoxButtons.OK, MessageBoxIcon.Error)

            Dim cancelDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)

            Me.Invoke(cancelDelegate, True)

            Exit Sub
        End Try
        Dim length As Long = theResponse.ContentLength 'Size of the response (in bytes)

        Dim safedelegate As New ChangeTextsSafe(AddressOf ChangeTexts)
        Me.Invoke(safedelegate, length, 0, 0, 0) 'Invoke the TreadsafeDelegate

        Dim writeStream As New IO.FileStream(Me.whereToSave, IO.FileMode.Create)

        'Replacement for Stream.Position (webResponse stream doesn't support seek)
        Dim nRead As Integer

        'To calculate the download speed
        Dim speedtimer As New Stopwatch
        Dim currentspeed As Double = -1
        Dim readings As Integer = 0

        Do

            If BackgroundWorker1.CancellationPending Then 'If user aborts download
                Exit Do
            End If

            speedtimer.Start()

            Dim readBytes(4095) As Byte
            Dim bytesread As Integer = theResponse.GetResponseStream.Read_
						(readBytes, 0, 4096)

            nRead += bytesread
            Dim percent As Short = (nRead * 100) / length

            Me.Invoke(safedelegate, length, nRead, percent, currentspeed)

            If bytesread = 0 Then Exit Do

            writeStream.Write(readBytes, 0, bytesread)

            speedtimer.Stop()

            readings += 1
            If readings >= 5 Then 'For increase precision, _
			' the speed is calculated only every five cycles
                currentspeed = 20480 / (speedtimer.ElapsedMilliseconds / 1000)
                speedtimer.Reset()
                readings = 0
            End If
        Loop

        'Close the streams
        theResponse.GetResponseStream.Close()
        writeStream.Close()

        If Me.BackgroundWorker1.CancellationPending Then

            IO.File.Delete(Me.whereToSave)

            Dim cancelDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)

            Me.Invoke(cancelDelegate, True)

            Exit Sub

        End If

        Dim completeDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)

        Me.Invoke(completeDelegate, False)

End Sub

此代码使用委托来调用主线程上的方法,并将有关下载进度的数据传递给它们。

此代码不支持 FTP 下载,但可以轻松修改以支持此功能。

恢复下载

可以修改代码以允许恢复下载。在第一次使用 HttpWebRequest 对象之前添加此代码。

theRequest.AddRange(whereYouWantToStart) '<- add this

您还需要将 FileStream 实例的 Position 属性设置为要恢复下载的位置。因此,请确保在取消下载之前也保存此位置。

Dim writeStream As New IO.FileStream(Me.whereToSave, IO.FileMode.Open)
writeStream.Position = whereYouWantToStart

计算速度

该代码包含内置的下载速度计算,使用 StopWatch 类。这将每下载 5 个数据包返回另一个结果。请注意,您也可以手动计算速度,并使用计时器以更规则的间隔获取数据。

© . All rights reserved.