Ich brauchte ein BackupScript, welches möglichst zügig arbeitet und eine Fortschrittsanzeige hat.
Bin dabei gestern von einer XCopy-Variante auf Robocopy (kopiert nur die Differenz) umgestiegen und wollte euch die Backupfunktion nicht vorenthalten. Ich glaube es waren schon einige Nachfragen nach einer Fortschrittsanzeige bei Robocopy und eine Lösung habe ich nicht finden können.
Hier meine Idee:
_Robocopy_WithProgress() V1.01
; #FUNCTION# ===============================================================
; Name...........: _RobocopyBackup_WithProgress()
; Description ...: Erstellt ein Backup der angegebenen Quelle im Zielordner,
; unter Zuhilfenahme von Robocopy Version XP010. Während
; des Backupvorgangs wird eine Progressbar angezeigt,
; welche auf Basis der Datei-/Ordneranzahl arbeitet.
; Syntax.........: _RobocopyBackup_WithProgress($sourceDir, $destDir)
; Parameters ....: $sourceDir - Quellverzeichnis
; $destDir - Zielverzeichnis
; Return values .: Success - 1
; Failure - 0
; Required ......: #include <File.au3>
; Microsoft Robocopy.exe Version XP010
; Author ........: [email='micha_he@autoit.de'][/email]
; Version .......: V1.01
; Date ..........: 13.02.2012
; Thanks to .....: [email='gigx@autoit.de'][/email] (_CopyWithProgress)
; [email='AdamUL@autoitscript.com'][/email] (_ProcessGetExitCode)
; [email='PsaltyDS@autoitscript.com'][/email] (_ProcessGetExitCode)
; History .......: V1.00 Erstrelease
; V1.01 Unnötige TEE-Option vom Testlauf entfernt
; ==========================================================================
Func _RobocopyBackup_WithProgress($srcDir, $destDir)
Local $pid, $geschafft, $GesamtAnzahl, $aDirSize
Local $hRun, $iExit1 , $iExit2
FileInstall("Robocopy.exe", @TempDir & "\Robocopy.exe")
If StringRight($srcDir, 1) = "\" Then $srcDir = StringTrimRight($srcDir, 1)
If StringRight($destDir, 1) = "\" Then $destDir = StringTrimRight($destDir, 1)
If Not FileExists($destDir) Then DirCreate($destDir)
ProgressOn("Backup-Fortschritt...", "", "", 10, 10, 16)
$aDirSize = DirGetSize($srcDir, 1)
$GesamtAnzahl = $aDirSize[1] + $aDirSize[2]
$pid = Run('"' & @TempDir & '\Robocopy" "' & $srcDir & '" "' & $destDir & '" /XN /XC /XO /IS /NOCOPY /E /R:0 /NP /NDL /NJH /NJS /LOG:"' & @TempDir & '\count.log"', @TempDir, @SW_HIDE)
$hRun = _ProcessGetHandle($pid)
Sleep(200)
Do
$geschafft = _FileCountLines(@TempDir & '\count.log') - 1
If $geschafft < 0 Then $geschafft = 0
If $geschafft > $GesamtAnzahl Then $geschafft = $GesamtAnzahl
ProgressSet($geschafft/$GesamtAnzahl*100, $geschafft & ' / ' & $GesamtAnzahl & ' Dateien/Ordner')
Sleep(100)
Until Not ProcessExists($pid)
$iExit1 = _ProcessGetExitCode($hRun)
_ProcessCloseHandle($hRun)
$pid = Run('"' & @TempDir & '\Robocopy" "' & $srcDir & '" "' & $destDir & '" /MIR /COPY:DAT /R:0 /NP /NJH /NJS /LOG+:"' & @TempDir & '\count.log"', @TempDir, @SW_HIDE)
$hRun = _ProcessGetHandle($pid)
Sleep(200)
Do
$geschafft = _FileCountLines(@TempDir & '\count.log') - 2
If $geschafft < 0 Then $geschafft = 0
If $geschafft > $GesamtAnzahl Then $geschafft = $GesamtAnzahl
ProgressSet($geschafft/$GesamtAnzahl*100, $geschafft & ' / ' & $GesamtAnzahl & ' Dateien/Ordner')
Sleep(100)
Until Not ProcessExists($pid)
ProgressSet(100, $geschafft & ' / ' & $GesamtAnzahl & ' Dateien/Ordner')
$iExit2 = _ProcessGetExitCode($hRun)
_ProcessCloseHandle($hRun)
FileDelete(@TempDir & '\count.log')
If FileExists(@TempDir & '\Robocopy.exe') Then FileDelete(@TempDir & '\Robocopy.exe')
Sleep(1000)
ProgressOff()
If $iExit1 >= 4 Or $iExit2 >= 4 Then Return 0
Return 1
EndFunc ;==> _RobocopyBackup_WithProgress
; Return handle of given PID
Func _ProcessGetHandle($iPID)
Local Const $PROCESS_QUERY_INFORMATION = 0x0400
Local $avRET = DllCall("kernel32.dll", "ptr", "OpenProcess", "int", $PROCESS_QUERY_INFORMATION, "int", 0, "int", $iPID)
If @error Then
Return SetError(1, 0, 0)
Else
Return $avRET[0]
EndIf
EndFunc ;==>_ProcessGetHandle
; Close process handle
Func _ProcessCloseHandle($hProc)
Local $avRET = DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hProc)
If @error Then
Return SetError(1, 0, 0)
Else
Return 1
EndIf
EndFunc ;==>_ProcessCloseHandle
; Get process exit code from handle
Func _ProcessGetExitCode($hProc)
Local $t_ExitCode = DllStructCreate("int")
Local $avRET = DllCall("kernel32.dll", "int", "GetExitCodeProcess", "ptr", $hProc, "ptr", DllStructGetPtr($t_ExitCode))
If @error Then
Return SetError(1, 0, 0)
Else
Return DllStructGetData($t_ExitCode, 1)
EndIf
EndFunc ;==>_ProcessGetExitCode