Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

FileCopy Progress


  • Please log in to reply
11 replies to this topic
fischgeek
  • Moderators
  • 1074 posts
  • Last active: Jul 07 2015 06:27 PM
  • Joined: 20 Apr 2009

I've looked at all the UrlDownloadToFile Progress topics, but I can't seem to get those methodologies to work for a FileCopy. I know I should be grabbing the file size in a loop, but how do I make the script work so once it hits the FileCopy command it doesn't just stop there until that's complete. It needs to run asynchronously.

 

Psuedo code

FileGetSize, fileSize, source
FileCopy, source, targetFile
Loop,
{
   GuiControl,, prog, % updateBySomeInteger
   FileGetSize, xferSize, targetFile
}
until fileSize = xferSize

The second the script reaches the "FileCopy" command (line 2 up there) it completes that first then moves on thus passing through the loop. How can I get this done?



rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
Off the top of my head:
  • Open the file as a File Object
  • Get the file size
  • Write out a certain percentage of the file
  • Update progress
  • Loop back to 3, unless you have written the entire file
  • close the file
It's probably a lot more complicated than that biggrin.gif, but that's where I would start.

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


Alpha Bravo
  • Members
  • 1687 posts
  • Last active: Nov 07 2015 03:06 PM
  • Joined: 01 Sep 2011

http://www.autohotke...ck/#entry136263



fischgeek
  • Moderators
  • 1074 posts
  • Last active: Jul 07 2015 06:27 PM
  • Joined: 20 Apr 2009

@rbrtryn - what do you mean by "write out a certain percentage of the file"?

 

@Alpha Bravo - Thanks for the link. Looks like they're using a DllCall to accomplish this. I'm starting to think that there is no "simple" way to do this. :S



rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
Let's assume that you are copying a binary file. Let's further assume that the file is 100K in size. You could use File.RawRead() (or maybe even just FileRead) to get the file into memory. Then write 1K blocks of data to the destination file using File.RawWrite(), updating the progress after each block is sent. The numbers are, of course, just examples.

If it is a text file, it is even easier:
  • Use FileRead to get the file into memory
  • Use StringReplace FileTxt, FileTxt, `r`n, `r`n, UseErrorLevel to get the number of lines in the file.
  • use a parsing loop to write the lines to the file, updating the progress as you go

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


fischgeek
  • Moderators
  • 1074 posts
  • Last active: Jul 07 2015 06:27 PM
  • Joined: 20 Apr 2009

File Object! - I haven't used RawRead/Write yet, but I will definitely look into this! Thank you!

 

This will suffice for now though until I have time to test out the File Object

Gui, _Main_:Default
Gui, Add, Button, w100 gGo, Go
Gui, Show
 
Gui, _Prog_:Default
Gui, Add, Progress, vprog 0x8
return
 
Go:
{
    Gui, _Prog_:Show
    SetTimer, UpdateProg, 1000
    MsgBox, I am doing something
    SetTimer, UpdateProg, Off
    Gui, _Prog_:Hide
    return
}
 
UpdateProg:
{
    Gui, _Prog_:Default
    Loop, 100
    {
        GuiControl,, prog, %A_Index%
        Sleep, 100
    } 
    return
}
 
GuiClose:
{
    ExitApp
}


fischgeek
  • Moderators
  • 1074 posts
  • Last active: Jul 07 2015 06:27 PM
  • Joined: 20 Apr 2009

Okay. I was looking into because I just couldn't get it off my mind. But, I must be using it wrong.

file := "C:\SomeFile.exe"
FileGetSize, fileSize, %file%
msgbox, % File.RawRead(var,fileSize)
msgbox, % var

both come up blank



MilesAhead
  • Members
  • 578 posts
  • Last active: Feb 29 2016 05:15 PM
  • Joined: 21 Jan 2009

If the files aren't very large or numerous you might consider using the shell.  The shell file functions handle progress and stuff like target overwrite dialogs for you.  They do tend to be slow. But can be convenient.  You can call them using DllCall.


"Some people, when confronted with a problem, think I know, I'll use regular expressions.  Now they have two problems."

- Jamie Zawinski


rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
You have to use FileOpen to get a File object before you can use the File object methods.

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
An example of copying a binary file with progress bar.
; Autoexecute
    #NoEnv
    #SingleInstance force
	
    InputFile := A_Desktop "\Input.jpg"
    OutputFile := A_Desktop "\Output.jpg"
    Source := FileOpen(InputFile, "r")
    Dest := FileOpen(OutputFile, "w")
    Incr := Ceil(Source.Length / 100)
    
    Progress cbGreen
    
    while not Source.AtEOF {
        Source.RawRead(Data, Incr)
        Dest.RawWrite(Data, Incr)
        Progress %A_Index%
    }
    
    Progress Off
    Source.Close()
    Dest.Close()
return

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


jbngar
  • Members
  • 3 posts
  • Last active: Nov 13 2013 12:45 AM
  • Joined: 31 Aug 2006

Hi guys - I couldn't find a non-complicated way to do this, so here's a workaround solution that uses a command prompt to do the copying while the progress bar is displayed.

I'm sure you can tidy it up and get it looking even better:

#b:: 
{
sourcefile=D:\Documents on D\movies\zoolander.avi
targetfile=K:\john\zoolander.avi
filedelete %targetfile%
run, cmd
sendinput copy /y "%sourcefile%" "%targetfile%"{enter}
loop {

filegetsize, sourcefilesize, %sourcefile%, M
filegetsize, targetfilesize, %targetfile%, M
progresspercent:=targetfilesize/sourcefilesize*100
progress, %progresspercent%, %targetfilesize% of %sourcefilesize% MB copied,, Copying...
sleep, 500


}until targetfilesize = sourcefilesize

progress, off

sendinput, exit{enter}
exit
}


Flipeador
  • Members
  • 67 posts
  • Last active: Dec 29 2015 11:22 AM
  • Joined: 12 May 2014
;AHK1.1.22.09 Unicode
Result := FileCopyEx(A_SysDir() "\imageres.dll", A_Desktop "\~imageres.dll",, "InfoCopy")
Progress, Off
MsgBox % "Return: " Result "`nErrorLevel: " ErrorLevel
ExitApp
InfoCopy(TotalBytes, BytesWritten, Percent) {
Progress, % Percent, %Percent%  `% Completado...`nBytes Totales: %TotalBytes%`nBytes Escritos: %BytesWritten%
if GetKeyState("w") ;stop  copying while "w" is pressed
return 3
else {
Sleep 250
return 1
}
Sleep 250
}


FileCopyEx(Filename, Dest := "", OverWrite := false, Func := "", Flags := "") {
SplitPath, Filename, ffn ;, dir, ext, fn, drive
Dest := Dest=""?A_WorkingDir "\" ffn:GetFullPathName(Dest)
if !(OverWrite) && (FileExist(Dest)) 
return false, ErrorLevel := 2
if !(IsObject(sf:=FileOpen(Filename, "r-wd"))) || !(IsObject(df:=FileOpen(Dest, "w-rwd", sf.Encoding)))
return false, sf.Close(), ErrorLevel := 4
RemainingBytes := Bytes := sf.Length, Count := Floor(Bytes/1000000), df.Length := Count?1000000:Bytes, TotalBytesWritten := 0
Loop, % (Count?Count+1:1) {
if (RemainingBytes>999999) {
VarSetCapacity(Data, 1000000), sf.RawRead(Data, 1000000)
, TotalBytesWritten := TotalBytesWritten+df.RawWrite(Data, 1000000)
} else {
VarSetCapacity(Data, RemainingBytes), sf.RawRead(Data, RemainingBytes)
, TotalBytesWritten := TotalBytesWritten+df.RawWrite(Data, RemainingBytes)
if !(Count) && (IsFunc(Func)) && (%Func%(Bytes, TotalBytesWritten, 100)=0)
return TotalBytesWritten=Bytes, sf.Close(), df.Close(), ErrorLevel := 3
break
} RemainingBytes := RemainingBytes-1000000, VarSetCapacity(Data, 0), df.Length := TotalBytesWritten
if (IsFunc(Func)) {
Percent(10000, TotalBytesWritten / Bytes, Percent)
if ((fReturn:=%Func%(Bytes, TotalBytesWritten, RemainingBytes>999999?Percent:100))=false) {
return false, sf.Close(), df.Close(), ErrorLevel := 3
} else if (fReturn=2) {
Func := ""
} else if (fReturn=3) {
while !(%Func%(Bytes, TotalBytesWritten, RemainingBytes>999999?Percent:100)=1)
Sleep, 1000
}}} sf.Close(), df.Close()
if (Ok:=(TotalBytesWritten=Bytes)) {
if !(Flags[1]) ;CopyAttrib
FileSetAttrib("+" FileGetAttrib(Filename), Dest)
if !(Flags[2]) ;CopyTime
FileSetTime(FileGetTime(Filename, "MCA"), Dest)
} return Ok, ErrorLevel := !Ok
}


FileSetAttrib(Attributes, FilePattern, OperateOnFolders := false, Recurse := false) {
FileSetAttrib, %Attributes%, %FilePattern%, %OperateOnFolders%, %Recurse%
return !ErrorLevel
}


FileGetAttrib(Filename) {
FileGetAttrib, OutputVar, %Filename%
return OutputVar
}


FileGetTime(Filename, WhichTime := "M") {
OutputVar := []
Loop, Parse, % WhichTime
{ FileGetTime, Time, %Filename%, %WhichTime%
if !(Time="")
OutputVar.Push(Time)
} return OutputVar.MaxIndex()=1?OutputVar[1]:OutputVar
}


FileSetTime(Time := "", FilePattern := "", WhichTimeMCA := "M", OperateOnFolders := false, Recurse := false) {
if IsObject(Time)
for k, v in Time
FileSetTime, %v%, %FilePattern%, % k=1?"M":k=2?"C":k=3?"A":k, %OperateOnFolders%, %Recurse%
else Loop, Parse, % WhichTimeMCA
FileSetTime, %Time%, %FilePattern%, %A_LoopField%, %OperateOnFolders%, %Recurse%
return !ErrorLevel
}




Percent(num, Percent, ByRef OutputPercent := "", Places := 2) {
return Float(num-(i:=(num/100)*Percent), "0." Places), OutputPercent := IsByRef(OutputPercent)?Round(i, Places):""
}




Float(num, Type := "0.2") {
return Format("{:" Type (RegExReplace(Type, "[^fegaEGA]")?"":"f") "}", num)
}




GetFullPathName(Filename, ByRef Length := "") {
Size := DllCall("Kernel32.dll\GetFullPathNameW", "Str", Filename, "UInt", 0, "Ptr", 0, "PtrP", 0, "UShort"), VarSetCapacity(OutputVar, Size * 2, 0) 
, Length := DllCall("Kernel32.dll\GetFullPathNameW", "Str", Filename, "UInt", Size, "Str", OutputVar, "PtrP", 0, "UShort")
return Length?RTrim(OutputVar, "\"):Filename, ErrorLevel := !Length
}




A_SysDir() {
static SysDir
if !(SysDir)
uSize := DllCall("kernel32.dll\GetSystemDirectoryW", "Ptr", 0, "UInt", 0)
, VarSetCapacity(SysDir, uSize * 2, 0)
, DllCall("kernel32.dll\GetSystemDirectoryW", "Str", SysDir, "UInt", uSize)
return SysDir
}