التقدم أثناء نسخ الملفات الكبيرة (نسخ العنصر والكتابة التقدم؟)

StackOverflow https://stackoverflow.com/questions/2434133

سؤال

هل هناك أي طريقة لنسخ ملف كبير حقا (من خادم واحد إلى آخر) في PowerShell وعرض تقدمها؟

هناك حلول هناك لاستخدام تقدم الكتابة بالاقتران مع حلقات لنسخ العديد من الملفات وتقدم العرض. ومع ذلك، لا يمكنني العثور على أي شيء من شأنه إظهار تقدم ملف واحد.

أي أفكار؟

هل كانت مفيدة؟

المحلول

أنا لم أسمع عن التقدم مع Copy-Item. وبعد إذا كنت لا ترغب في استخدام أي أداة خارجية، فيمكنك تجربة التدفقات. يختلف حجم المخزن المؤقت، يمكنك تجربة قيم مختلفة (من 2 كيلوبايت إلى 64 كيلو بايت).

function Copy-File {
    param( [string]$from, [string]$to)
    $ffile = [io.file]::OpenRead($from)
    $tofile = [io.file]::OpenWrite($to)
    Write-Progress -Activity "Copying file" -status "$from -> $to" -PercentComplete 0
    try {
        [byte[]]$buff = new-object byte[] 4096
        [int]$total = [int]$count = 0
        do {
            $count = $ffile.Read($buff, 0, $buff.Length)
            $tofile.Write($buff, 0, $count)
            $total += $count
            if ($total % 1mb -eq 0) {
                Write-Progress -Activity "Copying file" -status "$from -> $to" `
                   -PercentComplete ([int]($total/$ffile.Length* 100))
            }
        } while ($count -gt 0)
    }
    finally {
        $ffile.Dispose()
        $tofile.Dispose()
        Write-Progress -Activity "Copying file" -Status "Ready" -Completed
    }
}

نصائح أخرى

يبدو وكأنه حلا أفضل بكثير لاستخدام Bitstransfer، يبدو أنه يأتي OOTB على معظم أجهزة Windows باستخدام PowerShell 2.0 أو أكبر.

Import-Module BitsTransfer
Start-BitsTransfer -Source $Source -Destination $Destination -Description "Backup" -DisplayName "Backup"

بديل هذا الخيار يستخدم شريط التقدم المحرز الأصلي ...

$FOF_CREATEPROGRESSDLG = "&H0&"

$objShell = New-Object -ComObject "Shell.Application"

$objFolder = $objShell.NameSpace($DestLocation) 

$objFolder.CopyHere($srcFile, $FOF_CREATEPROGRESSDLG)
cmd /c copy /z src dest

ليس PowerShell نقية، ولكن الملف القابل للتنفيذ في PowerShell ويعرض التقدم المحرز في النسب المئوية

عدلت الكود من Stej (الذي كان رائعا، فقط ما أحتاجه!) لاستخدام أكبر مخزن مؤقت، [طويل] للملفات الأكبر واستخدامها SYSTEM.DIAGNOSTICS.STOPWATCH فئة لتتبع الوقت المنقضي وقدر الوقت.

إضافة أيضا الإبلاغ عن معدل النقل أثناء النقل وإخراج الوقت المنقضي العام ومعدل النقل العام.

باستخدام المخزن المؤقت 4 ميغابايت (4096 * 1024 بايت) للحصول على أفضل من Win7 النسخ الإنتاجية الأصلية من NAS إلى عصا USB على الكمبيوتر المحمول عبر WiFi.

في قائمة المهام:

  • إضافة معالجة خطأ (الصيد)
  • التعامل مع قائمة ملف get-childitem كمدخلات
  • أشرطة تقدم متداخلة عند نسخ ملفات متعددة (ملف X من y،٪ إذا تم نسخ إجمالي البيانات إلخ)
  • المعلمة الإدخال لحجم المخزن المؤقت

لا تتردد في استخدام / تحسين :-)

function Copy-File {
param( [string]$from, [string]$to)
$ffile = [io.file]::OpenRead($from)
$tofile = [io.file]::OpenWrite($to)
Write-Progress `
    -Activity "Copying file" `
    -status ($from.Split("\")|select -last 1) `
    -PercentComplete 0
try {
    $sw = [System.Diagnostics.Stopwatch]::StartNew();
    [byte[]]$buff = new-object byte[] (4096*1024)
    [long]$total = [long]$count = 0
    do {
        $count = $ffile.Read($buff, 0, $buff.Length)
        $tofile.Write($buff, 0, $count)
        $total += $count
        [int]$pctcomp = ([int]($total/$ffile.Length* 100));
        [int]$secselapsed = [int]($sw.elapsedmilliseconds.ToString())/1000;
        if ( $secselapsed -ne 0 ) {
            [single]$xferrate = (($total/$secselapsed)/1mb);
        } else {
            [single]$xferrate = 0.0
        }
        if ($total % 1mb -eq 0) {
            if($pctcomp -gt 0)`
                {[int]$secsleft = ((($secselapsed/$pctcomp)* 100)-$secselapsed);
                } else {
                [int]$secsleft = 0};
            Write-Progress `
                -Activity ($pctcomp.ToString() + "% Copying file @ " + "{0:n2}" -f $xferrate + " MB/s")`
                -status ($from.Split("\")|select -last 1) `
                -PercentComplete $pctcomp `
                -SecondsRemaining $secsleft;
        }
    } while ($count -gt 0)
$sw.Stop();
$sw.Reset();
}
finally {
    write-host (($from.Split("\")|select -last 1) + `
     " copied in " + $secselapsed + " seconds at " + `
     "{0:n2}" -f [int](($ffile.length/$secselapsed)/1mb) + " MB/s.");
     $ffile.Close();
     $tofile.Close();
    }
}

ليس هذا ما اخاف منه. لن أوصي باستخدام عنصر النسخ لهذا على أي حال. لا أعتقد أنه تم تصميمه ليكون قويا مثل Robocopy.exe لدعم إعادة المحاولة التي تريد أن ترغب في نسخ ملفات كبيرة للغاية عبر الشبكة.

تقوم هذه الوظيفة العودية بنسخ الملفات والدلائل بشكل متكرر من مسار المصدر إلى مسار الوجهة

إذا كان الملف موجودا بالفعل على مسار الوجهة، فسيتم نسخها فقط مع ملفات أحدث.

Function Copy-FilesBitsTransfer(
        [Parameter(Mandatory=$true)][String]$sourcePath, 
        [Parameter(Mandatory=$true)][String]$destinationPath, 
        [Parameter(Mandatory=$false)][bool]$createRootDirectory = $true)
{
    $item = Get-Item $sourcePath
    $itemName = Split-Path $sourcePath -leaf
    if (!$item.PSIsContainer){ #Item Is a file

        $clientFileTime = Get-Item $sourcePath | select LastWriteTime -ExpandProperty LastWriteTime

        if (!(Test-Path -Path $destinationPath\$itemName)){
            Start-BitsTransfer -Source $sourcePath -Destination $destinationPath -Description "$sourcePath >> $destinationPath" -DisplayName "Copy Template file" -Confirm:$false
            if (!$?){
                return $false
            }
        }
        else{
            $serverFileTime = Get-Item $destinationPath\$itemName | select LastWriteTime -ExpandProperty LastWriteTime

            if ($serverFileTime -lt $clientFileTime)
            {
                Start-BitsTransfer -Source $sourcePath -Destination $destinationPath -Description "$sourcePath >> $destinationPath" -DisplayName "Copy Template file" -Confirm:$false
                if (!$?){
                    return $false
                }
            }
        }
    }
    else{ #Item Is a directory
        if ($createRootDirectory){
            $destinationPath = "$destinationPath\$itemName"
            if (!(Test-Path -Path $destinationPath -PathType Container)){
                if (Test-Path -Path $destinationPath -PathType Leaf){ #In case item is a file, delete it.
                    Remove-Item -Path $destinationPath
                }

                New-Item -ItemType Directory $destinationPath | Out-Null
                if (!$?){
                    return $false
                }

            }
        }
        Foreach ($fileOrDirectory in (Get-Item -Path "$sourcePath\*"))
        {
            $status = Copy-FilesBitsTransfer $fileOrDirectory $destinationPath $true
            if (!$status){
                return $false
            }
        }
    }

    return $true
}

شون كيرني من مهلا، النص البرمجي! مقالات لديه حل وجدته بشكل جيد للغاية.

Function Copy-WithProgress
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
            ValueFromPipelineByPropertyName=$true,
            Position=0)]
        $Source,
        [Parameter(Mandatory=$true,
            ValueFromPipelineByPropertyName=$true,
            Position=0)]
        $Destination
    )

    $Source=$Source.tolower()
    $Filelist=Get-Childitem "$Source" –Recurse
    $Total=$Filelist.count
    $Position=0

    foreach ($File in $Filelist)
    {
        $Filename=$File.Fullname.tolower().replace($Source,'')
        $DestinationFile=($Destination+$Filename)
        Write-Progress -Activity "Copying data from '$source' to '$Destination'" -Status "Copying File $Filename" -PercentComplete (($Position/$total)*100)
        Copy-Item $File.FullName -Destination $DestinationFile
        $Position++
    }
}

ثم لاستخدامها:

Copy-WithProgress -Source $src -Destination $dest

يحتوي تريفور سوليفان على الكتابة حول كيفية إضافة أمر يسمى نسخة itemwithprogress. إلى Powershell على Robocopy.

أكره أن تكون الشخص الذي يصطدم بموضوع قديم، لكنني وجدت هذا المنشور مفيدا للغاية. بعد إجراء اختبارات الأداء على مقتطفات من قبل Stej والتحويل من قبل Graham Gold، بالإضافة إلى اقتراح BITS من قبل Nacht، لقد اسفت من ذلك:

  1. أنا حقا أمر يحب Graham بتقديرات زمنية وقراءات السرعة.
  2. أنا أيضا حقا أعجبني زيادة السرعة كبيرة في استخدام البتات كطريقة التحويل الخاصة بي.

واجهت القرار بين الاثنين ... لقد وجدت أن البيتسترانز فايت الوضع غير المتزامن. لذلك هنا هو نتيجة دمج بلدي اثنين.

function Copy-File {
    param([string]$from, [string]$to)

    try {
        $job = Start-BitsTransfer -Source $from -Destination $to `
                   -Description "Moving: $from => $to" `
                   -DisplayName "Backup" -Asynchronous

        # Start stopwatch
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
        Write-Progress -Activity "Connecting..."

        while ($job.JobState.ToString() -ne "Transferred") {
            switch ($job.JobState.ToString()) {
                "Connecting" {
                    break
                }
                "Transferring" {
                    $pctcomp = ($job.BytesTransferred / $job.BytesTotal) * 100
                    $elapsed = ($sw.elapsedmilliseconds.ToString()) / 1000

                    if ($elapsed -eq 0) {
                        $xferrate = 0.0
                    } else {
                        $xferrate = (($job.BytesTransferred / $elapsed) / 1mb);
                    }

                    if ($job.BytesTransferred % 1mb -eq 0) {
                        if ($pctcomp -gt 0) {
                            $secsleft = ((($elapsed / $pctcomp) * 100) - $elapsed)
                        } else {
                            $secsleft = 0
                        }

                        Write-Progress -Activity ("Copying file '" + ($PathName.Split("\") | Select -last 1) + "' @ " + "{0:n2}" -f $xferrate + "MB/s") `
                                       -PercentComplete $pctcomp `
                                       -SecondsRemaining $secsleft
                    }
                    break
                }
                "Transferred" {
                    break
                }
                Default {
                    throw $job.JobState.ToString() + " unexpected BITS state."
                }
            }
        }

        $sw.Stop()
        $sw.Reset()
    } finally {
        Complete-BitsTransfer -BitsJob $job
        Write-Progress -Activity "Completed" -Completed
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top