webclient中的进度条

时间:2017-05-31 21:46:47

标签: powershell handler webclient

所以,我有一个脚本显示从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一次只能下载一个文件。

当然,我知道。

3 个答案:

答案 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)

我看到两个可能的概念:

  1. 动态创建([scriptblock]::Create)匿名函数,例如:
  2. $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
    }
    
    1. 创建自己的自定义后台工作程序(线程):
    2. 有关示例,请参阅:PowerShell: Job Event Action with Form not executed

      • 在主线程中使用进度条构建您的UI
      • 对于每个FTP下载:
        • 创建共享(隐藏)窗口控件(例如.TextBox[$Id]
        • 启动新的后台工作人员并共享相关控件,例如:
          $SyncHash = [hashtable]::Synchronized(@{TextBox = $TextBox[$Id]})
      • 从WebWorker中更新共享$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()

让读者练习如何判断下载已经完成。