Jump to content
Sign in to follow this  
mrider

File copy progress bar

Recommended Posts

mrider

Here's my problem - I'm copying a modestly large file across a WAN link, and I'd like to provide the user with a progress bar. I've tried the following methods:

FileCopy( $fileName, ".", 1 )

and

RunWait( @COMSPEC & ' /C copy "' & $fileName & '" .', "", @SW_HIDE )

and with both methods, the file reports it's full size immediately. So I can't figure out how to tell how much of the file has actually copied across the network. If the file were to report the amount that's actually copied, then I could do a bit of simple math to create a progress bar.

I know I could use Windows copy which would natively create a progress bar, but then the user would know where the file is coming from. This isn't necessarily a problem per se (it's not top secret or anything like that), it is an implementation detail that I'd rather not confuse my users with.

We're all on Win2K pro if that makes a difference...

Any suggestions?


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
Gigglestick

I haven't tried this, but I think you could do it something like this:

1. Use FileFindFirstFile and FileFindNextFile (or _RunDOS("dir /a/s/b ' & $fullpath) and capture the output, looking for "Total Files Listed:" and then taking the number of files for your maximum in the progress bar.

2. Then you can run your CMD with Run instead of RunWait and loop, watching StdoutRead and counting the files, updating the progress bar for each file that is output to StdOut.

If you're interested, I'll find a way to do all this with COM objects. I ran across some similar code in MSDN a week or so back anyway.


My UDFs: ExitCodes

Share this post


Link to post
Share on other sites
Gigglestick

maybe take a look at this

http://www.autoitscript.com/forum/index.ph...opic=11888&hl=#

hope it helps

8)

<{POST_SNAPBACK}>

Nevermind my comment. Go with this!

EDIT: Actually, I personally don't care for the Windows Explorer copy method. I'd rather have my own progress dialog. mrider might like your solution, though. Thanks.

Edited by c0deWorm

My UDFs: ExitCodes

Share this post


Link to post
Share on other sites
mrider

Wow. It sure looks like the copy with progress script will work. Thanks * 1,000,000!!


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
mrider

Oh - regarding post #3. Thanks for the suggestion, but there's only one file. That's the problem. If there were multiple files, I'd just poll the directory and run the progress as:

int(( numFilesNeeded / numFilesFound ) * 100 ).

I was trying to do something like:

int(( finalFileSize / currentFileSize ) * 100 )

Unfortunately it reports it's final size immediately...


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
Gigglestick

Unfortunately it reports it's final size immediately...

<{POST_SNAPBACK}>

If the file's too small for AutoIt to show a progress, then how is it possible that the Windows Explorer dialog shows at all?! I don't think the Explorer "Copying..." window even shows unless it knows it's going to show a progress for at least a second or more.

How big is this file you're copying?


My UDFs: ExitCodes

Share this post


Link to post
Share on other sites
mrider

The ultimate file is moderately large - say 5Mb. Considering the WAN speed, it'll probably take around a minute to download.

For testing purposes, I'm copying a 400Mb file (that's right 400 megabytes) so that I have plenty of time to see a progress bar. It's a much faster link, but the copy time is about the same. Roughly a minute.

When I use Windows Explorer, I get a progress bar showing progress on that one file. As I said, I could force a Windows Explorer window open, navigate to the directory, select the file, select copy, navigate to the destination directory, select paste - and I'd get a progress bar. IMHO that leaves too many things that the user could screw up though.

When I use AutoIt's FileCopy I get no progress bar - even though it takes about a minute. Using both AutoIt's file copy and the DOS copy command, I can't ask for current size of the destination file - because both Windows Explorer and AutoIt's FileGetSize reports the final size immediately - even though there's still stuff to copy.

It looks like the link provided won't work. When I run the scipt I get the following error message:

Line 37  (File "C:\Program Files\AutoIt3\Include\FileCopy.au3"):

$SHFILEOPSTRUCT = DllStructCreate("int;uint;ptr;ptr;uint;int;ptr;ptr")

$SHFILEOPSTRUCT = ^ ERROR

Error: Unknown function name.

So back to square one...


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
mrider

I hate to admit defeat, but it looks like I'm done. I tried the following, thinking that I could watch the progress as the bytes go by one at a time, but the script doesn't copy the file faithfully.

while 1
    $char = FileRead( $fileIN, 1 );
    If @error = -1 Then ExitLoop;
    FileWrite( $fileOUT, $char );
    If @error = -1 Then ExitLoop;
WEnd

Probably because it's a binary file, and AutoIt tries to read an actual character.

Maybe I can convince the powers that be to put it on a web or ftp server available only internally. I bet InetGet reports correctly.


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
Sokko

It looks like the link provided won't work. When I run the scipt I get the following error message:

You'll need the latest beta version of AutoIt to make it work. A lot of user-defined functions use DllStruct functions, which are not available in the current production version.

Share this post


Link to post
Share on other sites
Gigglestick

Have you considered Robocopy? Check out the Windows 2003 Resource Kit for the latest version "XP010". I think you can capture the percentage via StdoutRead and just make your progress bar show that percentage. Plus I personally think Robocopy is faster and more reliable than Explorer.... at the very least its progress per file is more helpful.


My UDFs: ExitCodes

Share this post


Link to post
Share on other sites
mrider

Well, the latest beta worked with my code. And I get a nice progress bar. I'm downloading the RK tools now, and I'll take a look at Robocopy. I also tested InetGet, and it in fact correctly displays the file size as it goes.

Thanks everyone - I really appreciate the help. I don't know what I'll use as a final solution, but I have three different things that at least do something.


How's my riding? Dial 1-800-Wait-There

Trying to use a computer with McAfee installed is like trying to read a book at a rock concert.

Share this post


Link to post
Share on other sites
Matt Houston

...I think you can capture the percentage via StdoutRead and just make your progress bar show that percentage. Plus I personally think Robocopy is faster and more reliable than Explorer.... at the very least its progress per file is more helpful.

Hi Everyone,

has somebody tried to use robocopy in order to produce a progressbar? I tried to use it in combination with StdoutRead which is working fine - but i don't have any idea how to parse the captured stuff.

Is it possible to "StdoutRead line by line"?

Greetings!

MattHouston

Share this post


Link to post
Share on other sites
shovetech

Like others, I too wanted a way to display a progress bar while copying a file. Unfortunately, since I'm using WinPE 2.0, I can't get a native explorer-type progress dialog, as the necessary DLL's aren't included. I wrote my own that only relies on the 'copy' command with any version of Windows (including WinPE).

Attached is the version I wrote. It's meant to be compiled an run as a stand-alone executable.

Any improvements and suggestions would be appreciated.

Update:

v1.1.6: Fixed a bug where copying to/from the root of a drive (ex. c:\, d:\, etc.) was handled incorrectly.

v1.1.5: Fixed a bug where if /k switch is given and file transfer was too fast, peak speed would show 0 bytes/s.

v1.1.4: Fixed a bug where empty directories were reporting failure, although copy operation was successful.

v1.1.3: adds two progress bars for current progress, and total progress

if /k switch is given, shows peak (highest) transfer rate during operation

v1.1.0: supports copying directories

CopyFileProgress_v1.1.6.au3

Edited by shovetech

Share this post


Link to post
Share on other sites
parsifal

Mmm, if i try to copy in a root of hard disk five an error (Could not replace g:\).

my test is : CopyFileProgress_v1.1.5.exe /k E:\Test g:

Something wrong?

Share this post


Link to post
Share on other sites
parsifal

Bug:

sample:

CopyFileProgress_v1.1.5.exe /k E:\test c:\pippo

where test is

test--> Folder -->Subfolder --> File

copyng files (works fine) CopyFileProgress make in the root of E:\ the folder "pippo" with the structure of folder "test" without files.

Share this post


Link to post
Share on other sites
shovetech

Mmm, if i try to copy in a root of hard disk five an error (Could not replace g:\).

my test is : CopyFileProgress_v1.1.5.exe /k E:\Test g:

Something wrong?

Thank you for the feedback. I updated to v1.1.6 which fixes this issue. Also, make sure you end the drive letter with a backslash (ex. g:\) when specifying source/destination.

Share this post


Link to post
Share on other sites
jp10558

Thank you for the feedback. I updated to v1.1.6 which fixes this issue. Also, make sure you end the drive letter with a backslash (ex. g:\) when specifying source/destination.

Is there a UDF version of this?

Also, I'm seeing a bug with the total amount to copy / progress bar display when copying a folder with several nested folders in it from a mapped network drive to a local folder. My first test is already at 62 MB / 27 MB ...

Share this post


Link to post
Share on other sites
Chimaera

Have you considered Robocopy? Check out the Windows 2003 Resource Kit for the latest version "XP010". I think you can capture the percentage via StdoutRead and just make your progress bar show that percentage. Plus I personally think Robocopy is faster and more reliable than Explorer.... at the very least its progress per file is more helpful.

XP010 is the early version best and most useful version Ive found through much practice with robocopy is XP026 (XP027 is vista and above only)

Share this post


Link to post
Share on other sites
digitalteck

I downloaded the file from below to try since I could not get the one on the other post to work.

Here is my error I get Pic attached. Also I hope I put my Sourse and Dest link on the right line 52 and 53.

; Copies a file/directory using the native Windows copy command, but

; displays statistics while copying.

; The only dependency is 'copy.exe', which is available on every Windows system.

; Works especially good in a WinPE environment where no copy GUI is available.

;

; v1.1.6:

; - Fixed bug: Copying to/from the root directory of a drive (c:\, d:\, etc.)

; was handled incorrectly.

; v1.1.5:

; - Fixed bug: Peak speed would display 0 bytes/s for small files

; v1.1.4:

; - Fixed bug: empty directories would report failure

; v1.1.3:

; - Add current file progress bar (above total progress bar)

; - Add check for file/dir size after copy operation is complete

; - Add 'Peak speed' on display after copy operation is complete

; v1.1.2:

; - Add internal byte decimal place ($bytedecimalplace) global var

; for displaying any byte measurement data

; v1.1.1:

; - Shorten path and file names on GUI display

; v1.1.0:

; - Adds copying directory support

; - Re-write some code and better organized code

; v1.0.0:

; - Initial release

;

#include <GUIConstants.au3>

#include <GUIConstantsEx.au3>

#include <ProgressConstants.au3>

#include <ButtonConstants.au3>

#Include <GuiButton.au3>

#Include <File.au3>

Opt("GUICoordMode", 0)

Opt("GUIOnEventMode", 1)

Opt("MustDeclareVars", 1)

; Debug Mode

; If debug=1, then Debug Mode is turned on. This produces a lot

; of messages for debugging purposes.

; NOTE: This setting should be 0 for production use.

Global $debug = 0

Global $invalidChars = "/ : * ? < > | " & chr(34)

Global $forceoverwrite = 0

Global $showcopytime = 0

Global $noerror = 0

Global $displayhelp = 0

Global $title = "Copying files..."

Global $source = "C:\Users\John\Desktop\Test"

Global $destination = "C:\Users\John\Desktop\Test2"

Global $cmdopts = $CmdLine

Global $sourcetype = ""

Global $progress = 0

Global $fail = ""

If ($cmdopts[0] = 0) Then

displayHelp()

Exit

EndIf

; Loop through command args for switches

For $a = 1 to ($cmdopts[0])

Select

Case StringLower($cmdopts[$a]) = "/y"

$forceoverwrite = 1

Case StringLower($cmdopts[$a]) = "/noerror"

$noerror = 1

case StringLower(StringLeft($cmdopts[$a], 7)) = "/title:"

$title = StringSplit($cmdopts[$a], ":")

If ($title[2] <> "") Then

$title = $title[2]

Else

; set to empty

$title = ""

EndIf

case StringLower($cmdopts[$a]) = "/title"

; if no valid title is given, continue as normal

case StringLower($cmdopts[$a]) = "/k"

$showcopytime = 1

case $cmdopts[$a] = "/?"

$displayhelp = 1

Case Else

If ($a = ($cmdopts[0] - 1)) Then

$source = $cmdopts[($cmdopts[0] -1)]

ElseIf ($a = $cmdopts[0]) Then

$destination = $cmdopts[($cmdopts[0])]

Else

$displayhelp = 1

EndIf

EndSelect

Next

; If displayhelp = 1, display help message

If ($displayhelp = 1) Then

displayHelp()

Exit

EndIf

; Must specify both source and destination

If ($source = "" Or $destination = "") Then

errorMsg ("You must specify both source and destination files")

Exit

EndIf

; Check for illegal characters in source

If ( validPath(getDirectory($source)) = 0 Or _

validPath(getFilename($source)) = 0 ) Then

errorMsg ("Source file name invalid. File name cannot contain: " & @LF & $invalidChars)

Exit

EndIf

; Convert any relative paths into absolute paths

$source = _PathFull($source)

$destination = _PathFull($destination)

; Check that source file exist

If (FileExists($source)) Then

If (StringInStr(FileGetAttrib($source), "D", 0) = 0) Then

; if source is a file, (not directory)

$sourcetype = "file"

debugMsg ("Source is a file")

; if destination is directory, append source filename

If (StringInStr(FileGetAttrib($destination), "D", 0)) Then

If (StringRight($destination, 1) = "\") Then

; append only filename to destination, no \ required

$destination = $destination & getFilename($source)

Else

; append \ + source filename to destination

$destination = $destination & "\" & getFilename($source)

EndIf

debugMsg ("New destination " & $destination)

EndIf

Else

; if source is a diretory

$sourcetype = "dir"

; if destination is <drive>:\ append full source directory

If (getDirectory($destination) & getFilename($destination) = "\") Then

$destination = getDrive($destination) & getDirectory($source) & getFilename($source)

EndIf

debugMsg ("Source is a directory")

EndIf

Else

; if source does not exist

errorMsg ($source & " does not exist.")

Exit

EndIf

; Check for illegal characters in destination

If ( validPath(getDirectory($destination)) = 0 Or _

validPath(getFilename($destination)) = 0 ) Then

errorMsg ("Destination file name invalid. File name cannot contain: " & @LF & $invalidChars)

Exit

EndIf

; Check if source and destination are the same

If (StringUpper($source) = StringUpper($destination)) Then

errorMsg ("Source and destination are the same!")

Exit

EndIf

; If destination exist, ask if ok to overwrite

If (FileExists($destination)) Then

If ($forceoverwrite = 0) Then

; if response is No..

If (MsgBox(4 + 32 + 256, "Overwrite", $destination & " already exists. Overwrite?") = 7) Then

Exit

EndIf

EndIf

; remove destination

; if destination is a directory, use DirRemove

; if destination is a file, use FileDelete

If (StringInStr(FileGetAttrib($destination), "D", 0)) Then

; remove destination directory

debugMsg ("Removing directory " & $destination)

If (DirRemove ($destination, 1) = 0) Then

errorMsg ("Could not replace " & $destination)

Exit

EndIf

Else

; remove destination file

debugMsg ("Removing file " & $destination)

If (FileDelete($destination) = 0) Then

errorMsg ("Could not replace " & $destination)

Exit

EndIf

EndIf

EndIf

; Global GUI controls

Global $guiwin, $cancelbtn, $progressbar, $currentprogressbar, $msg, $index, $lblbytes

Global $lbltransfer, $lblspin, $lblfiles, $lblcurrentfile, $lbltime, $lbltotalprogress

Global $spin = "|"

Global $progresssubstring = ""

Global $pid = 0

Global $sourcesize = 0

Global $destinationsize = 0

Global $copyfiletime ; total time for copy operation

Global $statusrefresh = 1300 ; calulate time remain, speed, etc. interval

Global $progresstimer

Global $progressrefresh = 1000 ; display stats (time est/remain, speed) interval

Global $spintimer

Global $spinrefresh = 170 ; display top bar (bytes and spin) interval

Global $bytedecimalplace = 2

Global $peakspeed = 0

$guiwin = GUICreate($title, 300, 200)

$lblbytes = GUICtrlCreateLabel("Preparing...", 5, 5, 290)

$lblcurrentfile = GUICtrlCreateLabel("Cur. Source: " & $source & @LF & "Cur. Destination: " & $destination , -1, 21, 290, 26)

$currentprogressbar = GUICtrlCreateProgress(-1, 20, 290, 20, $PBS_SMOOTH)

$lbltotalprogress = GUICtrlCreateLabel("Total progress", -1, 21, 290, 26)

$progressbar = GUICtrlCreateProgress(-1, 20, 290, 20, $PBS_SMOOTH)

$lblfiles = GUICtrlCreateLabel("Source: " & $source & @LF & "Destination: " & $destination , -1, 21, 290, 30)

$lbltime = GUICtrlCreateLabel("", -1, 31, 290, 13)

$lbltransfer = GUICtrlCreateLabel("", -1, 14, 290, 13)

$cancelbtn = GUICtrlCreateButton("Cancel", 230, 15, 60)

GUICtrlSetOnEvent($cancelbtn, "cancelop")

GUISetOnEvent($GUI_EVENT_CLOSE, "cancelop")

GUISetState(@SW_SHOW)

; if source is file, copy file

; if source is directory, copy directory

; Get size of source

GUICtrlSetData($lblbytes, "Calculating size ...")

If ($sourcetype = "file") Then

$sourcesize = FileGetSize($source)

ElseIf ($sourcetype = "dir") Then

$sourcesize = DirGetSize($source)

EndIf

If ($sourcesize = -1) Then

errorMsg ("Could not retrieve size of " & $source)

Exit

EndIf

debugMsg ($source & " size: " & $sourcesize)

; Start the timer(s)

$copyfiletime = TimerInit()

$progresstimer = TimerInit()

; Start copying

If ($sourcetype = "file") Then

If (copyFile($source, $destination) = 0) Then

$fail = $fail & @LF & $destination

EndIf

ElseIf ($sourcetype = "dir") Then

; if any file fails to copy, $fail is updated inside copyDir

copyDir ($source, $destination)

EndIf

; Stop timer

$copyfiletime = TimerDiff($copyfiletime)

; Get size of destination

GUICtrlSetData($lblbytes, "Checking size ...")

If ($sourcetype = "file") Then

$destinationsize = FileGetSize($destination)

ElseIf ($sourcetype = "dir") Then

$destinationsize = DirGetSize($destination)

EndIf

If ($destinationsize = -1) Then

errorMsg ("Could not retrieve size of " & $destination)

Exit

EndIf

debugMsg ($destination & " size: " & $destinationsize)

; If destinationsize <> sourcesize, warn user

If ($destinationsize <> $sourcesize) Then

errorMsg ("Source and destination sizes are different.")

EndIf

; If fail is not empty, warn user

If ($fail <> "") Then

errorMsg ("Failed to copy:" & @LF & $fail)

EndIf

; If /k switch was given, leave dialog open

If ($showcopytime = 1) Then

; rename and re-map the "Cancel" button to "Close"

GUICtrlSetOnEvent($cancelbtn, "closeop")

GUISetOnEvent($GUI_EVENT_CLOSE, "closeop")

_GUICtrlButton_SetText ($cancelbtn, "Close")

; Update display status

Local $destbyteprefix = 0

Local $destbytesuffix = ""

Local $peakspeedprefix = 0

Local $peakspeedsuffix = ""

getByteSuffix($destinationsize, $destbyteprefix, $destbytesuffix)

getByteSuffix($peakspeed, $peakspeedprefix, $peakspeedsuffix)

GUICtrlSetData($lblbytes, "Total transfered: " & Round($destbyteprefix, $bytedecimalplace) & " " & $destbytesuffix)

GUICtrlSetData ($lblcurrentfile, "Current file:")

GUICtrlSetData($lblfiles, "Source: " & shortText($source) & @LF & "Destination: " & shortText($destination))

GUICtrlSetData($lbltransfer, "Peak speed: " & Round($peakspeedprefix, $bytedecimalplace) & " " & $peakspeedsuffix & "/s")

GUICtrlSetData($lbltime, "Total time: " & getTime($copyfiletime / 1000))

while (1)

Sleep (1000)

WEnd

EndIf

; End program

Exit

Func killproc($pid)

; kills a process

While (ProcessExists($pid))

ProcessClose($pid)

WEnd

EndFunc

Func closeop()

GUISetState(@SW_HIDE)

Exit

EndFunc

Func cancelop()

; if copy is in progress, kill proccess and remove destination

If (MsgBox(4 + 32 + 256, "Copy File Progress", "Are you sure you want to cancel file copy?") = 6) Then

GUICtrlSetState($cancelbtn, $GUI_DISABLE)

WinSetTitle($guiwin, "", $title & " canceling...")

GUICtrlSetData($lblbytes, "Canceling.....")

GUICtrlSetData($lbltransfer, "")

GUICtrlSetData($lbltime, "")

If ($pid > 0) Then killproc($pid)

If (FileExists($destination)) Then

GUICtrlSetData($lblbytes, "Removing " & $destination & " .....")

If ($sourcetype = "file") Then

debugMsg ("Removing file " & $destination)

FileDelete($destination)

ElseIf ($sourcetype = "dir") Then

debugMsg ("Removing directory " & $destination)

DirRemove($destination, 1)

EndIf

EndIf

Exit

EndIf

EndFunc

Func progressUpdate($insourcesize, $indestsize, $intransferspeed, $intimeremaining)

; Don't let progress bar above 100%

If ($progress > 100) Then

$progress = 100

EndIf

Local $sourceprefix = 0

Local $sourcesuffix = ""

getByteSuffix($insourcesize, $sourceprefix, $sourcesuffix)

Local $byteprefix = 0

Local $bytesuffix = ""

getByteSuffix($indestsize, $byteprefix, $bytesuffix)

Local $speedprefix = 0

Local $speedsuffix = ""

getByteSuffix($intransferspeed, $speedprefix, $speedsuffix)

Local $speedstring = ""

Local $timestring = ""

; set current speed

If ($intransferspeed > 0) Then

$speedstring = "Speed: " & Round($speedprefix, $bytedecimalplace) & " " & $speedsuffix & "/s"

EndIf

$progresssubstring = $speedstring

; set elapsed time and time remaining

$timestring = "Elapsed: " & getTime(timerdiff($copyfiletime) / 1000)

If (Int($intimeremaining) > 0) Then

$timestring = $timestring & " - Remaining: " & getTime($intimeremaining)

EndIf

; display spin at specified refresh time

If (TimerDiff($spintimer) > $spinrefresh) Then

$spintimer = TimerInit()

; Display spin

If (StringLen($spin) > 50) Then $spin = StringRight($spin, 1)

Switch StringRight($spin, 1)

Case "|"

$spin = StringReplace($spin, "|", "/", 1, 2)

Case "/"

$spin = StringReplace($spin, "/", "-", 1, 2)

Case "-"

$spin = StringReplace($spin, "-", "\", 1, 2)

Case "\"

$spin = StringReplace($spin, "\", ".", 1, 2) & ".|"

EndSwitch

GUICtrlSetData($lblbytes, Round($byteprefix, $bytedecimalplace) & " " & $bytesuffix & " / " & Round($sourceprefix, $bytedecimalplace) & " " & $sourcesuffix & " " & $spin)

EndIf

; only refresh at specified interval. this should minimize any flickering

If (TimerDiff($progresstimer) > $progressrefresh) Then

; restart progress timer

$progresstimer = TimerInit()

GUICtrlSetData($progressbar, $progress)

If ($intransferspeed > 0) Then

GUICtrlSetData($lbltransfer, $progresssubstring)

EndIf

GUICtrlSetData($lbltime, $timestring)

WinSetTitle($guiwin, "", $title & " " & $progress & " %")

ElseIf ($progress = 100) Then

; Always update status at progress of 100%

GUICtrlSetData($progressbar, $progress)

WinSetTitle($guiwin, "", $title & " " & $progress & " %")

EndIf

EndFunc

Func getTime($secs)

; Take time in seconds and convert to hours, mins, seconds, etc...

Local $seconds = $secs

Local $mins = 0

Local $hours = 0

Local $days = 0

Local $weeks = 0

Local $months = 0

Local $timestring = Int($seconds) & " secs"

If ($seconds > 60) Then

$mins = Int($seconds / 60)

$seconds = Int($seconds - ($mins * 60))

If ($seconds <= 0) Then

$timestring = $mins & " mins"

Else

$timestring = $mins & " mins " & $seconds & " secs"

EndIf

If ($mins > 60) Then

$hours = Int($mins / 60)

$mins = Int($mins - ($hours * 60))

If ($mins <= 0) Then

$timestring = $hours & " hours"

Else

$timestring = $hours & " hours " & $mins & " mins"

EndIf

If ($hours > 24) Then

$days = Int($hours / 24)

$hours = Int($hours - ($days * 24))

If ($hours <= 0) Then

$timestring = $days & " days"

Else

$timestring = $days & " days " & $hours & " hours"

EndIf

If ($days > 7) Then

$weeks = Int($days / 7)

$days = Int($days - ($weeks * 7))

If ($days <= 0) Then

$timestring = $weeks & " weeks"

Else

$timestring = $weeks & " weeks " & $days & " days"

EndIf

If ($weeks > 4) Then

$months = Int($weeks / 4)

$weeks = Int($weeks - ($months * 4))

If ($weeks <= 0) Then

$timestring = $months & " months"

Else

$timestring = $months & " months " & $weeks & " weeks"

EndIf

EndIf

EndIf

EndIf

EndIf

EndIf

Return $timestring

EndFunc

Func getByteSuffix ($bytes, ByRef $byteprefix, ByRef $bytesuffix)

Local $byte = 1

Local $kilobyte = ($byte * 1024)

Local $megabyte = ($kilobyte * 1024)

Local $gigabyte = ($megabyte * 1024)

Local $terabyte = ($gigabyte * 1024)

Local $petabyte = ($terabyte * 1024)

Select

Case $bytes > $petabyte

$byteprefix = ($bytes / $petabyte)

$bytesuffix = "PB"

Case $bytes > $terabyte

$byteprefix = ($bytes / $terabyte)

$bytesuffix = "TB"

Case $bytes > $gigabyte

$byteprefix = ($bytes / $gigabyte)

$bytesuffix = "GB"

Case $bytes > $megabyte

$byteprefix = ($bytes / $megabyte)

$bytesuffix = "MB"

Case $bytes > $kilobyte

$byteprefix = ($bytes / $kilobyte)

$bytesuffix = "KB"

Case Else

$byteprefix = $bytes

$bytesuffix = "bytes"

EndSelect

EndFunc

Func validPath ($input)

; search through invalidChars against input

Local $invalidCharArray = StringSplit($invalidChars, " ")

For $x = 1 to $invalidCharArray[0]

If (StringInStr($input, $invalidCharArray[$x])) Then

Return 0

EndIf

Next

Return 1

EndFunc

Func debugMsg ($inmsg)

; show debug message

If ($debug = 1) Then

MsgBox(0, "Debug", $inmsg)

EndIf

EndFunc

Func errorMsg($inmsg)

; displays error message

If ($noerror = 0) Then

MsgBox(16, "Error", $inmsg)

EndIf

EndFunc

Func copyFile($insource, $indest)

debugMsg ("Executing copyFile " & $insource & " -> " & $indest)

Local $sourcefilesize = FileGetSize($insource)

Local $destfilesize = 0

Local $sourceprefix = 0

Local $sourcesuffix = ""

Local $bytestransfered = 0

Local $transferspeed = 0

Local $transfersize = 0

Local $timeremaining = 0

Local $index = 1

Local $destsizeupdate = 0

Local $runcmd = ""

Local $procstats

Local $starttime

; set source size display

getByteSuffix($sourcefilesize, $sourceprefix, $sourcesuffix)

; update current file display

GUICtrlSetData ($lblcurrentfile, "Current file: " & getFilename(shortText($indest)))

; if destination's path doesn't exist, create it

If (FileExists(getDirectory($indest)) = 0) Then

debugMsg ("copyFile: Creating directory " & getDirectory($indest))

If (DirCreate(getDirectory($indest)) = 0) Then

Return 0

EndIf

EndIf

$runcmd = @ComSpec & " /c copy /y " & chr(34) & $insource & chr(34) & " " & Chr(34) & $indest & Chr(34)

debugMsg ("Command: " & $runcmd)

$starttime = TimerInit()

$pid = Run($runcmd, @ScriptDir, @SW_HIDE)

If ($pid = 0) Then

errorMsg ("Error running copy command")

Return 0

EndIf

$destsizeupdate = 0

While (ProcessExists($pid))

$procstats = ProcessGetStats($pid, 1)

If (IsArray($procstats) And UBound($procstats) > 4) Then

If (Int(timerdiff($starttime)) > $statusrefresh) Then

$transferspeed = Int($destinationsize / (TimerDiff($copyfiletime) / 1000))

If ($transferspeed > 0) Then

$timeremaining = (($sourcesize - $destinationsize) / $transferspeed)

EndIf

If ($transferspeed > $peakspeed) Then $peakspeed = $transferspeed

$transfersize = $procstats[4]

$starttime = TimerInit()

EndIf

; set global destinationsize (current transfer size minus previous destfilesize) = bytestransfered

$destinationsize = ($destinationsize + ($procstats[4] - $destfilesize))

$destsizeupdate = ($destsizeupdate + ($procstats[4] - $destfilesize))

$destfilesize = $procstats[4]

If ($destfilesize > $sourcefilesize) Then

$destfilesize = $sourcefilesize

EndIf

EndIf

; Update current file's progress

GUICtrlSetData($currentprogressbar, Int(($destfilesize / $sourcefilesize) * 100))

; Update overall progress display

$progress = Int(($destinationsize / $sourcesize) * 100)

progressUpdate($sourcesize, $destinationsize, $transferspeed, $timeremaining)

$index = ($index + 1)

WEnd

; After copy finished, display destination file size

debugMsg ("Copy file finished")

$destfilesize = FileGetSize($indest)

; if file copy was too fast, update global destination size

If ($destsizeupdate < $destfilesize) Then

$destinationsize = ($destinationsize + ($destfilesize - $destsizeupdate))

debugMsg ("Adding to destinationsize: " & ($destfilesize - $destsizeupdate))

EndIf

; If destination file doesn't exist, display error

If (FileExists($indest) = 0) Then

errorMsg ("Could not create file " & $indest)

Return 0

EndIf

; Compare source file size and destination file size

debugMsg("Source file size: " & $sourcefilesize)

debugMsg("Destination file size: " & $destfilesize)

If ($sourcefilesize <> $destfilesize) Then

FileDelete($indest)

Return 0

EndIf

; Update current file's progress

GUICtrlSetData($currentprogressbar, Int(($destfilesize / $sourcefilesize) * 100))

; Update transfer speed (now that file copy is finished)

$transferspeed = Int($destinationsize / (TimerDiff($copyfiletime) / 1000))

If ($transferspeed > 0) Then

$timeremaining = (($sourcesize - $destinationsize) / $transferspeed)

EndIf

If ($transferspeed > $peakspeed) Then $peakspeed = $transferspeed

; Update overall progress

$progress = Int(($destinationsize / $sourcesize) * 100)

progressUpdate($sourcesize, $destinationsize, $transferspeed, $timeremaining)

Return 1

EndFunc

Func copyDir($insource, $indest)

Local $search

Local $cursearchitem

Local $sourcepath = ""

Local $destpath = ""

; if destination ($indest) doesn't exist, create it first

If (FileExists($indest) = 0) Then

debugMsg ("copyDir: Creating directory " & $indest)

If (DirCreate($indest) = 0) Then

errorMsg ("Failed to create directory " & $indest)

Return 0

EndIf

EndIf

; search through current directory

; if @error = 1, directory is empty, return 1

$search = FileFindFirstFile ($insource & "\*.*")

If (@error = 1) Then Return 1

If ($search = -1) Then

errorMsg ("Error getting " & $insource & " contents")

Exit

EndIf

While 1

$cursearchitem = FileFindNextFile($search)

If @error Then ExitLoop

$sourcepath = $insource & "\" & $cursearchitem

$destpath = $indest & "\" & $cursearchitem

If (StringInStr(StringUpper(FileGetAttrib($sourcepath)), "D")) Then

; if search is a directory, create it and search for files inside

debugMsg("Creating directory " & $destpath)

If (FileExists($destpath) = 0) Then

If (DirCreate($destpath) = 0) Then

debugMsg("Failed to create directory " & $destpath)

FileClose($search)

Return 0

EndIf

EndIf

debugMsg("Traversing " & $sourcepath)

If (copyDir($sourcepath, $destpath) = 0) Then

$fail = $fail & @LF & $destpath

EndIf

Else

; if search is a file, copy it

debugMsg("Copying file " & $sourcepath & " -> " & $destpath)

If (copyFile($sourcepath, $destpath) = 0) Then

$fail = $fail & @LF & $destpath

EndIf

EndIf

WEnd

FileClose($search)

Return 1

EndFunc

Func displayHelp()

; displays help message

; if noerror <> 0, don't display help message

Local $helpmsg

If ($noerror = 0) Then

$helpmsg = "CopyFileProgress.exe [options] source destination" & @CRLF _

& " [options]:" & @CRLF _

& " /noerror = disable error messages" & @CRLF _

& " /? = display this help message" & @CRLF _

& " /y = suppress prompt to overwrite destination" & @CRLF _

& " /k = keep dialog open after file copy" & @CRLF _

& " /title:<title> = set title of copy dialog box" & @CRLF _

& @CRLF _

& " source = source file/directory" & @CRLF _

& " destination = destination file/directory" & @CRLF

MsgBox(64, "Help", $helpmsg)

EndIf

EndFunc

Func getDrive ($inpath)

; returns the drive for a given path

Local $tmp

Local $returnstring

_PathSplit($inpath, $returnstring, $tmp, $tmp, $tmp)

Return $returnstring

EndFunc

Func getDirectory ($inpath)

; returns the directory for a given path

Local $tmp

Local $returnstring

_PathSplit($inpath, $tmp, $returnstring, $tmp, $tmp)

Return $returnstring

EndFunc

Func getFilename ($inpath)

; returns the filename for a given path

Local $tmp

Local $tmpfilename

Local $tmpfileext

Local $returnstring

_PathSplit($inpath, $tmp, $tmp, $tmpfilename, $tmpfileext)

$returnstring = $tmpfilename & $tmpfileext

Return $returnstring

EndFunc

Func shortText($instring)

; shortens a line of text and places '...' in the middle

; returns string result

Local $maxlen = 35

Local $resultstring = ""

If (StringLen($instring) > $maxlen) Then

$resultstring = StringLeft($instring, (Int($maxlen / 2) - 2))

$resultstring = $resultstring & "..."

$resultstring = $resultstring & StringRight($instring, (Int($maxlen / 2) - 1))

Else

$resultstring = $instring

EndIf

Return $resultstring

EndFunc

post-77883-0-75082100-1359686148_thumb.j

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×