DownloadFileAsync下载多个文件不完整

时间:2022-11-10 20:06:52
我要下载多个文件,在循环中的关键代码如下:

            Dim myWebClient As New WebClient()
            If myWebClient.IsBusy Then
                myWebClient.CancelAsync()
            End If

            Dim remoteUri As String = strOldPath
            If myWebClient.IsBusy Then
                myWebClient.CancelAsync()
            End If
            TxtBoxLog.Text = "正在下载:" + strOldPath & vbCrLf & TxtBoxLog.Text

            Dim uri As New Uri(remoteUri)
            myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)
            myWebClient.Dispose()
            myWebClient = Nothing
            TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text 

我发现下载文件还是非常快的,问题是有些文件没下载完成,有些只有一半,还有一些是0字节,不知道什么原因,恳请指教。

我在网上看到有说绑定 DownloadDataCompleted 事件,问题是我在这个循环下载中怎么处理呢?恳请指教,非常感谢!!

17 个解决方案

#1


你用的是异步下载,所以调用DownloadFileAsync后不要立即释放myWebClient资源
要等它下载完再释放,myWebClient有个下载进度事件,可以判断什么时候下载完


或者你干脆别用异步下载,直接 myWebClient.DownloadFile(New Uri(strOldPath), strNewPath)
这样后面就可以写释放代码

#2


myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)
'下面代码放到myWebClient下载进度事件里,并判断下载结束后调用
  myWebClient.Dispose()
  myWebClient = Nothing
  TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text  




myWebClient.DownloadFile(New Uri(strOldPath), strNewPath)
  myWebClient.Dispose()
  myWebClient = Nothing
  TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text  


#3


谢谢你的回复。DownloadFile是可以,但速度太慢了,DownloadFileAsync速度快了好多。你说的放到下载进度事件里,问题是我怎么来判断下载完成了呢?我在for循环中myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)下载,我怎么等待下载完了再下载下一个文件呢?请告知,谢谢

#4


首先要说明的是,异步下载并不会比同步下载快.它的好处是不阻塞线程,这样的你界面或其他任务可以同时执行.
另外你应该看一下DownloadFileCompleted的说明.
你需要自己添加DownloadFileCompleted事件的处理方法,并关联到你的webclient实例.这样当你的下载完成时,会触发DownloadFileCompleted事件,而你在你的事件处理方法中,就可以知道文件下载完了.
另外如果你需要知道进度,需要关联DownloadProgressChanged事件.

#5


理论上,应该可以在循环中连续调用这个异步下载方法.调用后,方法会立即返回,而下载任务在后台线程会自动执行.只要网络正常,你的这些文件会被并行下载完成.
当然前提是webclient这个东西确实支持并行下载,这点我不确认.
如果你想在下载完一个内容后再下载另一个文件,那么就像我上面说的,将所有要下载的文件做到队列里.在DownloadFileCompleted中,按照队列里的顺序,调用DownloadFileAsync来下载下一个文件.

#6


感谢你们的热心回答,我正在自己研究,好像跟你们说的差不多,要是你们能提供具体代码或者示例就好了,呵呵呵

#7


不知道能看懂不?我写的比较简化,可能功能上跟你要的有点差距

Sub downloadfile(ByVal path As String)
        Dim client As New Net.WebClient
        AddHandler client.DownloadDataCompleted, AddressOf downloadfilecomplite
        client.DownloadFileAsync(New Uri(path), "FullFileName")
    End Sub

    Sub downloadfilecomplite(ByVal sender As Object, ByVal e As Net.DownloadDataCompletedEventArgs)
        '文件下完了,继续后面的
        downloadfile("nextFilePathToDown")
    End Sub

#8


引用 4 楼 missa 的回复:
首先要说明的是,异步下载并不会比同步下载快.


嗯,有质量的回复。

#9


谢谢你了。我准备用判断文件下载大小来循环等待:e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage。

#10


引用 3 楼 tangzhong 的回复:
谢谢你的回复。DownloadFile是可以,但速度太慢了,DownloadFileAsync速度快了好多。


你的所谓“快”是以根本没有下载完为代价的,这就印证了我常说(也是抄来)的:最高效的程序就是什么都不做。

异步下载只会让文件下载变慢!但是由于是在线程中,所以可以让线程切换(而不会在下载时阻塞),例如切换到主线程就可以处理键盘响应,切换到其它下载线程就可以并行处理下载过程。

#11


引用 9 楼 tangzhong 的回复:
谢谢你了。我准备用判断文件下载大小来循环等待:e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage。


循环是羸弱的,千万不要往循环方面去想问题,特别不要让你的主线程搞什么循环等待(那么你不过是用个异步编程语句来搞同步阻塞而已)。下载完之后,异步下载过程就会抛出事件,你应该在事件中处理善后工作,这才是异步编程。

#12


善用异步,你会发现处理问题原来是如此的简单.

#13


只用过downloadfile,这个更好用?

#14


引用 13 楼 bdxzq 的回复:
只用过downloadfile,这个更好用?
DownloadFileAsync绝对效率高多了,只是使用更复杂-对我来说

#15


引用 11 楼 sp1234 的回复:
循环是羸弱的,千万不要往循环方面去想问题,特别不要让你的主线程搞什么循环等待(那么你不过是用个异步编程语句来搞同步阻塞而已)。下载完之后,异步下载过程就会抛出事件,你应该……

我也知道这样不好,但你能告诉我怎么在异步下载的时候处理完成或者出错的事件么?再次贴出我的部分代码:
do
            Dim myWebClient As New WebClient()

            If myWebClient.IsBusy Then
                myWebClient.CancelAsync()
            End If

            Dim remoteUri As String = strOldPath
            If myWebClient.IsBusy Then
                '是否存在正在进行中的Web请求 
                myWebClient.CancelAsync()
            End If
            TxtBoxLog.Text = "正在下载:" + strOldPath & vbCrLf & TxtBoxLog.Text

            Dim uri As New Uri(remoteUri)
            AddHandler myWebClient.DownloadFileCompleted, AddressOf wc_DownloadFileCompleted
            '  Specify a progress notification handler.
            AddHandler myWebClient.DownloadProgressChanged, AddressOf wc_DownloadProgressChanged

            myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)
            TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text
while (如果还有文件要下载)

请告诉我怎么得知这个文件下载完了,继续下载其他文件。恳请告知怎么在DownloadFileCompleted、DownloadProgressChanged中处理?非常感谢!

#16


一早起来顶下,希望能得到大家的帮助。

#17


事件的关联只要添加一次就可以.不要在循环里反复做,这样等于事件的处理方法在被不断重置.
你现在做的实际是多文件并行下载,这个我还真不确定是否可以做到.
应该使用文件队列做串行下载,每个文件的下载是异步的,但文件和文件之间是一个队列关系.当前面的文件下载结束后,才下载后面的文件.
然后我没看到你的处理函数,这个其实也很简单.看到我上面写的例子了吗?
你只要在在完成事件里,给webclient一个新的下载地址(即队列中新的一个远程文件地址)就可以了.至于你怎么做这个队列,是用数组还是queue,这都可以你的习惯了.

#1


你用的是异步下载,所以调用DownloadFileAsync后不要立即释放myWebClient资源
要等它下载完再释放,myWebClient有个下载进度事件,可以判断什么时候下载完


或者你干脆别用异步下载,直接 myWebClient.DownloadFile(New Uri(strOldPath), strNewPath)
这样后面就可以写释放代码

#2


myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)
'下面代码放到myWebClient下载进度事件里,并判断下载结束后调用
  myWebClient.Dispose()
  myWebClient = Nothing
  TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text  




myWebClient.DownloadFile(New Uri(strOldPath), strNewPath)
  myWebClient.Dispose()
  myWebClient = Nothing
  TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text  


#3


谢谢你的回复。DownloadFile是可以,但速度太慢了,DownloadFileAsync速度快了好多。你说的放到下载进度事件里,问题是我怎么来判断下载完成了呢?我在for循环中myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)下载,我怎么等待下载完了再下载下一个文件呢?请告知,谢谢

#4


首先要说明的是,异步下载并不会比同步下载快.它的好处是不阻塞线程,这样的你界面或其他任务可以同时执行.
另外你应该看一下DownloadFileCompleted的说明.
你需要自己添加DownloadFileCompleted事件的处理方法,并关联到你的webclient实例.这样当你的下载完成时,会触发DownloadFileCompleted事件,而你在你的事件处理方法中,就可以知道文件下载完了.
另外如果你需要知道进度,需要关联DownloadProgressChanged事件.

#5


理论上,应该可以在循环中连续调用这个异步下载方法.调用后,方法会立即返回,而下载任务在后台线程会自动执行.只要网络正常,你的这些文件会被并行下载完成.
当然前提是webclient这个东西确实支持并行下载,这点我不确认.
如果你想在下载完一个内容后再下载另一个文件,那么就像我上面说的,将所有要下载的文件做到队列里.在DownloadFileCompleted中,按照队列里的顺序,调用DownloadFileAsync来下载下一个文件.

#6


感谢你们的热心回答,我正在自己研究,好像跟你们说的差不多,要是你们能提供具体代码或者示例就好了,呵呵呵

#7


不知道能看懂不?我写的比较简化,可能功能上跟你要的有点差距

Sub downloadfile(ByVal path As String)
        Dim client As New Net.WebClient
        AddHandler client.DownloadDataCompleted, AddressOf downloadfilecomplite
        client.DownloadFileAsync(New Uri(path), "FullFileName")
    End Sub

    Sub downloadfilecomplite(ByVal sender As Object, ByVal e As Net.DownloadDataCompletedEventArgs)
        '文件下完了,继续后面的
        downloadfile("nextFilePathToDown")
    End Sub

#8


引用 4 楼 missa 的回复:
首先要说明的是,异步下载并不会比同步下载快.


嗯,有质量的回复。

#9


谢谢你了。我准备用判断文件下载大小来循环等待:e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage。

#10


引用 3 楼 tangzhong 的回复:
谢谢你的回复。DownloadFile是可以,但速度太慢了,DownloadFileAsync速度快了好多。


你的所谓“快”是以根本没有下载完为代价的,这就印证了我常说(也是抄来)的:最高效的程序就是什么都不做。

异步下载只会让文件下载变慢!但是由于是在线程中,所以可以让线程切换(而不会在下载时阻塞),例如切换到主线程就可以处理键盘响应,切换到其它下载线程就可以并行处理下载过程。

#11


引用 9 楼 tangzhong 的回复:
谢谢你了。我准备用判断文件下载大小来循环等待:e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage。


循环是羸弱的,千万不要往循环方面去想问题,特别不要让你的主线程搞什么循环等待(那么你不过是用个异步编程语句来搞同步阻塞而已)。下载完之后,异步下载过程就会抛出事件,你应该在事件中处理善后工作,这才是异步编程。

#12


善用异步,你会发现处理问题原来是如此的简单.

#13


只用过downloadfile,这个更好用?

#14


引用 13 楼 bdxzq 的回复:
只用过downloadfile,这个更好用?
DownloadFileAsync绝对效率高多了,只是使用更复杂-对我来说

#15


引用 11 楼 sp1234 的回复:
循环是羸弱的,千万不要往循环方面去想问题,特别不要让你的主线程搞什么循环等待(那么你不过是用个异步编程语句来搞同步阻塞而已)。下载完之后,异步下载过程就会抛出事件,你应该……

我也知道这样不好,但你能告诉我怎么在异步下载的时候处理完成或者出错的事件么?再次贴出我的部分代码:
do
            Dim myWebClient As New WebClient()

            If myWebClient.IsBusy Then
                myWebClient.CancelAsync()
            End If

            Dim remoteUri As String = strOldPath
            If myWebClient.IsBusy Then
                '是否存在正在进行中的Web请求 
                myWebClient.CancelAsync()
            End If
            TxtBoxLog.Text = "正在下载:" + strOldPath & vbCrLf & TxtBoxLog.Text

            Dim uri As New Uri(remoteUri)
            AddHandler myWebClient.DownloadFileCompleted, AddressOf wc_DownloadFileCompleted
            '  Specify a progress notification handler.
            AddHandler myWebClient.DownloadProgressChanged, AddressOf wc_DownloadProgressChanged

            myWebClient.DownloadFileAsync(New Uri(strOldPath), strNewPath)
            TxtBoxLog.Text = "完成下载:" + strOldPath & vbCrLf & TxtBoxLog.Text
while (如果还有文件要下载)

请告诉我怎么得知这个文件下载完了,继续下载其他文件。恳请告知怎么在DownloadFileCompleted、DownloadProgressChanged中处理?非常感谢!

#16


一早起来顶下,希望能得到大家的帮助。

#17


事件的关联只要添加一次就可以.不要在循环里反复做,这样等于事件的处理方法在被不断重置.
你现在做的实际是多文件并行下载,这个我还真不确定是否可以做到.
应该使用文件队列做串行下载,每个文件的下载是异步的,但文件和文件之间是一个队列关系.当前面的文件下载结束后,才下载后面的文件.
然后我没看到你的处理函数,这个其实也很简单.看到我上面写的例子了吗?
你只要在在完成事件里,给webclient一个新的下载地址(即队列中新的一个远程文件地址)就可以了.至于你怎么做这个队列,是用数组还是queue,这都可以你的习惯了.