VB.NET下载管理器:如何让循环等待当前下载完成后再执行?
VB.NET批量下载:解决WebClient并发I/O报错问题
你遇到的核心问题是**WebClient.DownloadFileAsync是异步非阻塞方法**,循环里直接连续调用会导致WebClient同时执行多个下载操作,触发WebClient does not support concurrent I/O operations错误。要实现串行批量下载,需要利用WebClient的DownloadFileCompleted事件来触发下一个下载任务,而非用循环直接连续发起请求。
修改后的代码实现
Imports Microsoft.VisualBasic.ApplicationServices Imports Microsoft.VisualBasic.FileIO Imports System Imports System.Environment Imports System.IO Imports System.IO.Directory Imports System.Net Imports System.Net.Http Imports System.Threading Public Class Form1 Dim strLocation As String Dim strFile As String Dim intSeason As Integer Dim SAVE As String Dim Show As String Private WithEvents httpClient As WebClient ' 记录当前下载的链接索引 Private currentDownloadIndex As Integer = 0 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ofdBrowse.InitialDirectory = GetFolderPath(SpecialFolder.MyDocuments) ofdBrowse.Title = "Open file containing links" ofdBrowse.Filter = "Text Files|*.txt|All Files|*.*" ofdBrowse.ShowDialog() strLocation = ofdBrowse.FileName txtLocation.Text = strLocation strFile = strLocation Dim fileRead As New StreamReader(strFile) Dim Url As String Do While fileRead.Peek <> -1 Url = fileRead.ReadLine() If Mid(Url, 1, 1) = "[" Then intSeason = CInt(Mid(Url, 9, 1)) End If If Mid(Url, 1, 4) = "http" Then lbUrl.Items.Add(Url) End If Loop fileRead.Close() ' 释放文件资源 Show = InputBox("Enter the name of the show") End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click If lbUrl.Items.Count = 0 Then MessageBox.Show("No download links found!") Return End If ' 初始化下载索引 currentDownloadIndex = 0 httpClient = New WebClient ' 创建保存目录 Dim saveDir = $"{SpecialDirectories.Desktop}\{Show}\Season {intSeason}" If Not Exists(saveDir) Then CreateDirectory(saveDir) End If ' 启动第一个下载任务 StartNextDownload() End Sub ' 启动下一个下载的封装方法 Private Sub StartNextDownload() If currentDownloadIndex >= lbUrl.Items.Count Then MessageBox.Show("All downloads completed!") Return End If Dim URL = lbUrl.Items(currentDownloadIndex).ToString() SAVE = $"{SpecialDirectories.Desktop}\{Show}\Season {intSeason}\{Show} S{intSeason} E{currentDownloadIndex}.mkv" lbUrl.SelectedIndex = currentDownloadIndex httpClient.DownloadFileAsync(New Uri(URL), SAVE) End Sub Private Sub httpClientDownloadProgress(sender As Object, e As DownloadProgressChangedEventArgs) Handles httpClient.DownloadProgressChanged prgDownload.Value = e.ProgressPercentage End Sub ' 下载完成事件:触发下一个下载任务 Private Sub httpClient_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles httpClient.DownloadFileCompleted ' 可选:处理下载失败场景 If e.Error IsNot Nothing Then MessageBox.Show($"Download failed for item {currentDownloadIndex}: {e.Error.Message}") End If ' 索引递增,启动下一个下载 currentDownloadIndex += 1 StartNextDownload() End Sub End Class
关键修改说明
- 新增
currentDownloadIndex变量:跟踪当前正在下载的链接在ListBox中的位置,确保串行执行顺序。 - 拆分
StartNextDownload方法:统一处理单个下载任务的启动逻辑,避免重复代码。 - 利用
DownloadFileCompleted事件:每次下载完成(无论成功/失败)自动触发下一个下载,保证同一时间只有一个下载任务在运行。 - 资源优化:关闭
StreamReader避免文件资源泄漏;增加空链接列表判断,提升用户体验。
可选优化方向
- 增加链接有效性预校验,避免无效链接触发下载错误。
- 添加下载暂停/取消功能,通过
httpClient.CancelAsync()实现。 - 处理文件重名场景,避免覆盖已存在的文件。
内容的提问来源于stack exchange,提问作者Wilko84
相关产品推荐
相关产品推荐

