Jump to content

Copy with progress dialog...


ezzetabi
 Share

Recommended Posts

This code copies a folder content in an other folder that have to exist already.

It shows a progress dialog with percent completed (calculed over size) and a fraction of action done (calculated with number of files it have to copy and folders it have to create).

If a file can't be copied the function will make a logfile in the first avaiable place counting dest folder, original folder and @workingdir.

I posted something similar time ago, but I needed this again I improved it... so it is here again.

Func _CopyDirWithProgress($sOriginalDir, $sDestDir)
  ;$sOriginalDir and $sDestDir are quite selfexplanatory...
  ;This func returns:
  ; -1 in case of critical error, bad original or destination dir
  ;  0 if everything went all right
  ; >0 is the number of file not copied and it makes a log file
  ;  if in the log appear as error message '0 file copied' it is a bug of some windows' copy command that does not redirect output... 
   
   If StringRight($sOriginalDir, 1) <> '\' Then $sOriginalDir = $sOriginalDir & '\'
   If StringRight($sDestDir, 1) <> '\' Then $sDestDir = $sDestDir & '\'
   If $sOriginalDir = $sDestDir Then Return -1
   
   ProgressOn('Copying...', 'Making list of files...' & @LF & @LF, '', -1, -1, 18)
   Local $aFileList = _FileSearch($sOriginalDir)
   If $aFileList[0] = 0 Then
      ProgressOff()
      SetError(1)
      Return -1
   EndIf
   
   If FileExists($sDestDir) Then
      If Not StringInStr(FileGetAttrib($sDestDir), 'd') Then
         ProgressOff()
         SetError(2)
         Return -1
      EndIf
   Else
      DirCreate($sDestDir)
      If Not FileExists($sDestDir) Then
         ProgressOff()
         SetError(2)
         Return -1
      EndIf
   EndIf
   
   Local $iDirSize, $iCopiedSize = 0, $fProgress = 0
   Local $c, $FileName, $iOutPut = 0, $sLost = '', $sError
   Local $Sl = StringLen($sOriginalDir)
  
   _Quick_Sort($aFileList, 1, $aFileList[0])
   
   $iDirSize = Int(DirGetSize($sOriginalDir) / 1024)

   ProgressSet(Int($fProgress * 100), $aFileList[$c], 'Coping file:')
   For $c = 1 To $aFileList[0]
      $FileName = StringTrimLeft($aFileList[$c], $Sl)
      ProgressSet(Int($fProgress * 100), $aFileList[$c] & ' -> '& $sDestDir & $FileName & @LF & 'Total KiB: ' & $iDirSize & @LF & 'Done KiB: ' & $iCopiedSize, 'Coping file:  ' & Round($fProgress * 100, 2) & ' %   ' & $c & '/' &$aFileList[0])
      
      If StringInStr(FileGetAttrib($aFileList[$c]), 'd') Then
         DirCreate($sDestDir & $FileName)
      Else
         If Not FileCopy($aFileList[$c], $sDestDir & $FileName, 1) Then
            If Not FileCopy($aFileList[$c], $sDestDir & $FileName, 1) Then;Tries a second time
               If RunWait(@ComSpec & ' /c copy /y "' & $aFileList[$c] & '" "' & $sDestDir & $FileName & '">' & @TempDir & '\o.tmp', '', @SW_HIDE)=1 Then;and a third time, but this time it takes the error message
                  $sError = FileReadLine(@TempDir & '\o.tmp',1)
                  $iOutPut = $iOutPut + 1
                  $sLost = $sLost & $aFileList[$c] & '  ' & $sError & @CRLF
               EndIf
               FileDelete(@TempDir & '\o.tmp')
            EndIf
         EndIf
         
         FileSetAttrib($sDestDir & $FileName, "+A-RSH");<- Comment this line if you do not want attribs reset.
         
         $iCopiedSize = $iCopiedSize + Int(FileGetSize($aFileList[$c]) / 1024)
         $fProgress = $iCopiedSize / $iDirSize
      EndIf
   Next
  
   ProgressOff()
   
   If $sLost <> '' Then;tries to write the log somewhere.
      If FileWrite($sDestDir & 'notcopied.txt',$sLost) = 0 Then
         If FileWrite($sOriginalDir & 'notcopied.txt',$sLost) = 0 Then
            FileWrite(@WorkingDir & '\notcopied.txt',$sLost)
         EndIf
      EndIf
   EndIf
   
   Return $iOutPut
EndFunc  ;==>_CopyDirWithProgress

Func _FileSearch($sIstr, $bSF = 1)
  ; $bSF = 1 means looking in subfolders
  ; $sSF = 0 means looking only in the current folder.
  ; An array is returned with the full path of all files found. The pos [0] keeps the number of elements.
   Local $sIstr, $bSF, $sCriteria, $sBuffer, $iH, $iH2, $sCS, $sCF, $sCF2, $sCP, $sFP, $sOutPut = '', $aNull[1]
   $sCP = StringLeft($sIstr, StringInStr($sIstr, '\', 0, -1))
   If $sCP = '' Then $sCP = @WorkingDir & '\'
   $sCriteria = StringTrimLeft($sIstr, StringInStr($sIstr, '\', 0, -1))
   If $sCriteria = '' Then $sCriteria = '*.*'
   
  ;To begin we seek in the starting path.
   $sCS = FileFindFirstFile($sCP & $sCriteria)
   If $sCS <> - 1 Then
      Do
         $sCF = FileFindNextFile($sCS)
         If @error Then
            FileClose($sCS)
            ExitLoop
         EndIf
         If $sCF = '.' Or $sCF = '..' Then ContinueLoop
         $sOutPut = $sOutPut & $sCP & $sCF & @LF
      Until 0
   EndIf
   
  ;And after, if needed, in the rest of the folders.
   If $bSF = 1 Then
      $sBuffer = @CR & $sCP & '*' & @LF;The buffer is set for keeping the given path plus a *.
      Do
         $sCS = StringTrimLeft(StringLeft($sBuffer, StringInStr($sBuffer, @LF, 0, 1) - 1), 1);current search.
         $sCP = StringLeft($sCS, StringInStr($sCS, '\', 0, -1));Current search path.
         $iH = FileFindFirstFile($sCS)
         If $iH <> - 1 Then
            Do
               $sCF = FileFindNextFile($iH)
               If @error Then
                  FileClose($iH)
                  ExitLoop
               EndIf
               If $sCF = '.' Or $sCF = '..' Then ContinueLoop
               If StringInStr(FileGetAttrib($sCP & $sCF), 'd') Then
                  $sBuffer = @CR & $sCP & $sCF & '\*' & @LF & $sBuffer;Every folder found is added in the begin of buffer
                  $sFP = $sCP & $sCF & '\';                               for future searches
                  $iH2 = FileFindFirstFile($sFP & $sCriteria);         and checked with the criteria.
                  If $iH2 <> - 1 Then
                     Do
                        $sCF2 = FileFindNextFile($iH2)
                        If @error Then
                           FileClose($iH2)
                           ExitLoop
                        EndIf
                        If $sCF2 = '.' Or $sCF2 = '..' Then ContinueLoop
                        $sOutPut = $sOutPut & $sFP & $sCF2 & @LF;Found items are put in the Output.
                     Until 0
                  EndIf
               EndIf
            Until 0
         EndIf
         $sBuffer = StringReplace($sBuffer, @CR & $sCS & @LF, '')
      Until $sBuffer = ''
   EndIf
   
   If $sOutPut = '' Then
      $aNull[0] = 0
      Return $aNull
   Else
      Return StringSplit(StringTrimRight($sOutPut, 1), @LF)
   EndIf
EndFunc  ;==>_FileSearch

Func _Quick_Sort(ByRef $SortArray, $First, $Last);Larry's code
   Dim $Low, $High
   Dim $Temp, $List_Separator
   
   $Low = $First
   $High = $Last
   $List_Separator = StringLen($SortArray[ ($First + $Last) / 2])
   Do
      While (StringLen($SortArray[$Low]) < $List_Separator)
         $Low = $Low + 1
      WEnd
      While (StringLen($SortArray[$High]) > $List_Separator)
         $High = $High - 1
      WEnd
      If ($Low <= $High) Then
         $Temp = $SortArray[$Low]
         $SortArray[$Low] = $SortArray[$High]
         $SortArray[$High] = $Temp
         $Low = $Low + 1
         $High = $High - 1
      EndIf
   Until $Low > $High
   If ($First < $High) Then _Quick_Sort($SortArray, $First, $High)
   If ($Low < $Last) Then _Quick_Sort($SortArray, $Low, $Last)
EndFunc  ;==>_Quick_Sort
Edited by ezzetabi
Link to comment
Share on other sites

I am sort of a newbie at autoit... well not completley a newbie to it... but this code you posted make me look like a newbie! LOL!

This code sounds like something I would really like to implement into one of my autoit programs... but I can't seem to figure out what it is that I need to edit in your script to allow me to copy a specific directory. :(

Where would I tell it my Source/Destination directories?

Thanx a lot.

Proph

Link to comment
Share on other sites

I am sort of a newbie at autoit... well not completley a newbie to it... but this code you posted make me look like a newbie! LOL!

This code sounds like something I would really like to implement into one of my autoit programs... but I can't seem to figure out what it is that I need to edit in your script to allow me to copy a specific directory. :(

Where would I tell it my Source/Destination directories?

Thanx a lot.

Proph

<{POST_SNAPBACK}>

The first function is the one to use...

This is an example if how to copy one destination to another:

_CopyDirWithProgress("C:\Tempfiler\", "C:\Hello\")

Paste this in the script, and edit the locations.. and run :(

Link to comment
Share on other sites

Because of AutoIt, I have more free time to, um, write AutoIt scripts  :(

<{POST_SNAPBACK}>

Same thing here !

Currently I'm writing a script, which generates another script which again

generates a product for a third script :

The second script is made to make it easier to customize the third script,

and the first script is to making it easier for me to change the second

script :(:)

-Helge-

Link to comment
Share on other sites

Here a copy of a tipical message of a person that have really to much time free:

Sometimes I think you guys have too much time on your hands. :(

<{POST_SNAPBACK}>

Edited by ezzetabi
Link to comment
Share on other sites

Guest mikeomeara1

This is one beautiful script. Looks great, works better...truly stellar. Thanks for your hard work!!

Link to comment
Share on other sites

  • 2 months later...

@ezzetabi This script is very usefull and it works very well. :)

I am curious... would it be difficult to add some code to it to exclude certain directories from the copy path? I am trying to understand exactly how your code works... but I haven't been able to figure it out 100% So I have no clue what should be added and where.

Thanks to anyone who can be of assistance.

Link to comment
Share on other sites

@Proph

It is pretty easy, inside the _FileSeach function subfolders are added in the $sBuffer list. Just check if the name you want exclude matches. If it does do not add it.

But I can't do it outright, since I have no time... :|

@blitzkrg

dirmove is pretty straightforward, just changes those FileCopy with FileMove and just before the end use some thing like:

If $sLost <> '' Then;tries to write the log somewhere.
      If FileWrite($sDestDir & 'notcopied.txt',$sLost) = 0 Then
         If FileWrite($sOriginalDir & 'notcopied.txt',$sLost) = 0 Then
            FileWrite(@WorkingDir & '\notcopied.txt',$sLost)
         EndIf
      EndIf
   Else
      DirRemove ($sOriginalDir, 1)
   EndIf

So the original dir is removed if everything went allright, otherwise unmoved files and all folders will still stay there.

About subfolders or not, it is pretty useless. Coping only the root files is extemly easy. Help yourself.

Link to comment
Share on other sites

Guest zirex

Ezzatabi I'll just say iI think you are a AUTOIT Master..... great work ....!!! Hello to all from BOSNIA & Herzegovina....

Link to comment
Share on other sites

@Proph

It is pretty easy, inside the _FileSeach function subfolders are added in the $sBuffer list. Just check if the name you want exclude matches. If it does do not add it.

But I can't do it outright, since I have no time... :|

<{POST_SNAPBACK}>

Thanks for the explination. I should be able to figure it out from here. :) If I get stuck on it I will ask you for more help.

Thanks!

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...