所以,我有一个脚本显示从FTP下载进度。 我只是尝试了很多方法来解决这个问题。 其中一个结论是cmdlet Register-ObjectEvent是一个非常糟糕的主意。在Powershell中,异步事件的支持相当差...... 我在那里停了下来 -
$webclient.add_DownloadProgressChanged([System.Net.DownloadProgressChangedEventHandler]$webclient_DownloadProgressChanged )
....
$webclient_DownloadProgressChanged = {
param([System.Net.DownloadProgressChangedEventArgs]$Global:e)
$progressbaroverlay1.value=$e.ProgressPercentage
....
}
这个sript中的所有内容都可以正常工作,但你可以理解我这样做是为了一个文件。
但后来我开始思考 - 如何同时下载多个文件并在一个进度条中显示?
所以任何人都有什么好主意?或者解决此任务的最佳方法是什么?
P.S
WebClient一次只能下载一个文件。
当然,我知道。
答案 0 :(得分:0)
您可以使用BitsTransfer模块进行异步下载。 https://technet.microsoft.com/en-us/library/dd819420.aspx
显示3个文件的整个过程的示例代码,您指定了相同数量的网址和下载位置,您可以根据自己的喜好进行进一步处理,例如异常处理等:
Import-Module BitsTransfer
[string[]]$url = @();
$url += 'https://www.samba.org/ftp/talloc/talloc-2.1.6.tar.gz';
$url += 'https://e.thumbs.redditmedia.com/pF525auqxnTG-FFj.png';
$url += 'http://bchavez.bitarmory.com/Skins/DayDreaming/images/bg-header.gif';
[string[]]$destination = @();
$destination += 'C:\Downloads\talloc-2.1.6.tar.gz';
$destination += 'C:\Downloads\pF525auqxnTG-FFj.png';
$destination += 'C:\Downloads\bg-header.gif';
$result = Start-BitsTransfer -Source $url -Destination $destination -TransferType Download -Asynchronous
$downloadsFinished = $false;
While ($downloadsFinished -ne $true) {
sleep 1
$jobstate = $result.JobState;
if($jobstate.ToString() -eq 'Transferred') { $downloadsFinished = $true }
$percentComplete = ($result.BytesTransferred / $result.BytesTotal) * 100
Write-Progress -Activity ('Downloading' + $result.FilesTotal + ' files') -PercentComplete $percentComplete
}
答案 1 :(得分:0)
我看到两个可能的概念:
[scriptblock]::Create
)匿名函数,例如: $Id = 0
... | ForEach {
$webclient[$Id].add_DownloadProgressChanged([System.Net.DownloadProgressChangedEventHandler]{[scriptblock]::Create("
....
`$webclient_DownloadProgressChanged = {
param([System.Net.DownloadProgressChangedEventArgs]`$e)
`$Global:ProgressPercentage[$Id]=`$e.ProgressPercentage
`$progressbaroverlay1.value=(`$Global:ProgressPercentage | Measure-Object -Average).Average
....
"
$Id++
})
}
请注意,在这个想法中,你需要防止除了$Id
以外的所有内容直接用反引号解释。
或者,如果函数太大而无法读取,请简化[ScriptBlock]
:
[ScriptBlock]::Create("param(`$e); webclient_DownloadProgressChanged $Id `$e")
并调用全局函数:
$Global:webclient_DownloadProgressChanged($Id, $e) {
$Global:ProgressPercentage[$Id]=$e.ProgressPercentage
$progressbaroverlay1.value=($Global:ProgressPercentage | Measure-Object -Average).Average
}
有关示例,请参阅:PowerShell: Job Event Action with Form not executed
.TextBox[$Id]
)$SyncHash = [hashtable]::Synchronized(@{TextBox =
$TextBox[$Id]})
$SyncHash.TextBox.Text =
.Add_TextChanged
中捕获事件(例如.TextBox[$Id]
)
主线程.TextBox[$Id].Text
答案 2 :(得分:0)
我提出了相同类型的Scriptblock Create方法,但我确实使用了Register-ObjectEvent,或多或少成功。 Async下载作为后台作业发生,并使用事件将其进度传回主脚本。
$Progress = @{}
$Isos = 'https://cdimage.debian.org/debian-cd/current/i386/iso-cd/debian-8.8.0-i386-CD-1.iso',
'https://cdimage.debian.org/debian-cd/current/i386/iso-cd/debian-8.8.0-i386-CD-2.iso'
$Count = 0
$WebClients = $Isos | ForEach-Object {
$w = New-Object System.Net.WebClient
$null = Register-ObjectEvent -InputObject $w -EventName DownloadProgressChanged -Action ([scriptblock]::Create(
"`$Percent = 100 * `$eventargs.BytesReceived / `$eventargs.TotalBytesToReceive; `$null = New-Event -SourceIdentifier MyDownloadUpdate -MessageData @($count,`$Percent)"
))
$w.DownloadFileAsync($_, "C:\PATH_TO_DOWNLOAD_FOLDER\$count.iso")
$Count = $Count + 1
$w
}
$event = Register-EngineEvent -SourceIdentifier MyDownloadUpdate -Action {
$progress[$event.MessageData[0]] = $event.MessageData[1]
}
$Timer = New-Object System.Timers.Timer
Register-ObjectEvent -InputObject $Timer -EventName Elapsed -Action {
if ($Progress.Values.Count -gt 0)
{
$PercentComplete = 100 * ($Progress.values | Measure-Object -Sum | Select-Object -ExpandProperty Sum) / $Progress.Values.Count
Write-Progress -Activity "Download Progress" -PercentComplete $PercentComplete
}
}
$timer.Interval = 100
$timer.AutoReset = $true
$timer.Start()
让读者练习如何判断下载已经完成。