Sign in to follow this  
Followers 0
ivan

A little help appreciated

13 posts in this topic

Hi Guys!

As embarassed as I can be about putting forward this simple question, I can't figure out how i can combine the FileFindFirstFile and FileFindNextFile statements to build a list of subdirectory paths and files starting at @scriptdir like:

C:\Documents and Settings\ivan\img119.html

C:\Documents and Settings\ivan\xxxxxxxx\img119.jpg

C:\Documents and Settings\ivan\xxxxxxxx\yyyyyyyy\img12.html

C:\Documents and Settings\ivan\xxxxxxxx\yyyyyyyy\zzzzzzzzzzzzz\img12.jpg

ETC........................

I normally use batch files in ms-DOS with autoit, for example:

dir /a-d /b /on /s>FileList.txt

The -d parameter excludes subdirectories themselves, leaving just paths and file names, and the command dumps a neat list of files starting where I launch the bat file.

Unfortunately for me, this time the directory contains files with Spanish characters such as ñ, é, Á, and the likes, which are dumped with errors in unicode (8.3).

If I get a grip with FileFindFirstFile and FileFindNextFile I'll attach a code to this post, but all I managed so far is some really silly code. HELP PLEASE!!

If anyone has come across a solution to this problem before, I would really appreciate it if you could share it with me.

Thanks in advance.

IVAN

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

$a = _FileSearch(@scriptdir & '\*')

Func _FileSearch($sIstr)
  ; An array is returned with the full path of all files found. The pos [0] keeps the number of elements.
   Local $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
      While 1
         $sCF = FileFindNextFile($sCS)
         If @error Then
            FileClose($sCS)
            ExitLoop
         EndIf
         If $sCF = '.' Or $sCF = '..' Or StringInStr(FileGetAttrib($sCP & $sCF), 'd') Then ContinueLoop
         
         $sOutPut = $sOutPut & $sCP & $sCF & @LF
      WEnd
   EndIf
   
   $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
         While 1
            $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 search
               $iH2 = FileFindFirstFile($sFP & $sCriteria);          and checked with the criteria.
               If $iH2 <> - 1 Then
                  While 1
                     $sCF2 = FileFindNextFile($iH2)
                     If @error Then
                        FileClose($iH2)
                        ExitLoop
                     EndIf
                     If $sCF2 = '.' Or $sCF2 = '..' Or StringInStr(FileGetAttrib($sFP & $sCF2), 'd') Then ContinueLoop
                     
                     $sOutPut = $sOutPut & $sFP & $sCF2 & @LF;Found items are put in the Output.
                  WEnd
               EndIf
            EndIf
         WEnd
      EndIf
      $sBuffer = StringReplace($sBuffer, @CR & $sCS & @LF, '')
   Until $sBuffer = ''
   
   If $sOutPut = '' Then
      $aNull[0] = 0
      Return $aNull
   Else
      Return StringSplit(StringTrimRight($sOutPut, 1), @LF)
   EndIf
EndFunc  ;==>_FileSearch

Edit: _FileSearch altered so its should not return directories.

Edit2: Tested, it works with extended ASCII charactes (like èòà), but not with real unicode (like ありがとう )

Edited by ezzetabi

Share this post


Link to post
Share on other sites

I read your post better, if you just want to write a file list in a file. Change the return part of the UDF from

If $sOutPut = '' Then
      $aNull[0] = 0
      Return $aNull
   Else
      Return StringSplit(StringTrimRight($sOutPut, 1), @LF)
   EndIf

to

Return StringTrimRight($sOutPut, 1)

(and remove $aNull from declarations)

So the function will return a @lf separed list, ready to be write where you want.

Share this post


Link to post
Share on other sites

My script crashed? Very strange.

I tested also in very big folders but after a while it gave the correct result.

Anyway, if you improved the script share it with us improvements are always welcomed.

Share this post


Link to post
Share on other sites

I have 2 UDFs that you might want to look at. I designed them to return arrays containing large numbers of files. They even show a progress bar during the search.

Here's the link:

http://www.autoitscript.com/forum/index.ph...ic=12835&hl=UDF

Share this post


Link to post
Share on other sites

Does anyone know how to sort the array using the _FileSearch UDF according to the filezise?

Everything worked fine with the script shared by ezzetabi. Thanks a lot again, you don't cease to amaze me!

This next challenge might help a lot of us who keep backup copies of our files, without ever deleting them....

I've used ezzetabi's UDF to create a script which compares the byte size of each file with the rest of the files down the array and if they are equal, I run the DOS command FC /B file1 file2, which does a binary comparison of the said files.

If FC returns a text string on the second line saying that the there is no difference between the files (which i output to a text file), then it's safe to assume the files are identical and one of them can be deleted. Otherwise, if the output text file contains more than two lines, then the the files are different, so instead of waiting for hours, I close the fc.exe process using ProcessClose("fc.exe").

I'm not posting the script here yet as a precaution to other AUTOIT posters. In fact, I split the process in two scripts, the first one is ezzetabi's modified _FileSearch UDF to work with western-european characters, and which outputs the result to a text file. At this point I modify the list manually. Then I run my script made up of a for..next loop embedded in another to run FC.

As you can see, it is still a work in progress and if used incorrectly, someone might accidentally delete permanently a large number of files from their drive...

The advantage is that, after 4 days, I managed to recover over 7 gb of rubbish on my drive by deleting identical files (keeping a really disorganized file structure though), but it's ok as I kept a map of the drive's tree structure.

Basically i want to join the two scripts, and shorten the entire process, for which i'll need to sort the array according to the file size.

Any help would be greatly appreciated, as always.

Share this post


Link to post
Share on other sites

Does anyone know how to sort the array using the _FileSearch UDF according to the filezise?

You probably want to modify it to return a 2-dimensional array, where the filesize is stored in a 2nd column. Then you can use _ArraySort to sort based on that second column. Remember to set the file sizes as number, not string, to get the sort order correct.

If FC returns a text string on the second line saying that the there is no difference between the files (which i output to a text file), then it's safe to assume the files are identical and one of them can be deleted. Otherwise, if the output text file contains more than two lines, then the the files are different, so instead of waiting for hours, I close the fc.exe process using ProcessClose("fc.exe").

Neat trick. I believe there is a UDF for comparing files inside AutoIt, but I don't know how it's speed compares to FC

Share this post


Link to post
Share on other sites

Thanks. I had the same thought and i'm in the process of experimenting with a dummy folder and dummy files. I don't think i modified _FileSearch UDF correctly though as i've just seen the first results and the files don't match their respective size after sorting the array.

Share this post


Link to post
Share on other sites

This gives a slightly messy listing.

$x = Run(@ComSpec & " /c dir /a-d /b /on /s", "", @SW_HIDE,2)
$line = ""
While 1
    $line =$line & StdoutRead($x)
    If @error = -1 Then ExitLoop
Wend
FileWrite(@ScriptDir & "\file_list.txt",$line)

You will need the beta to run this.

Share this post


Link to post
Share on other sites

Thanks Steve.

As I mentioned on the opening topic, I first tried using the DOS command:

dir /a-d /b /on /s>FileList.txt

from a bat file but the directory contains Spanish characters such as ñ, é, Á, and the likes, and dir outputs rubbish on those characters.

I get a correct result with the _FileSearch UDF and I am trying to modify it so I can get a two dim array containing file name and size.

Share this post


Link to post
Share on other sites

give this a try

#include <Array.au3>

dim $dir[1], $dircount, $hDir, $temp
dim $file, $path, $attrib
dim $list

$dir[0] = "c:\download"
$dircount = 1
$x = 0

$hList = fileopen("filelist.txt", 2)

while ($x < $dircount)

    $hDir = filefindfirstfile($dir[$x]&"\*.*")
    if not ($hDir = -1) then
        
        $file = filefindnextfile($hDir)
        
        while not @error
            
            $path = $dir[$x]&"\"&$file
                            
            $attrib = filegetattrib($path)
                select
                    case ($file = ".")
                    ;nothing
                        
                    case ($file = "..")
                    ;nothing
                        
                    case (isDir($path))
                    ;msgbox(0,"Found Dir:", $file)
                        _arrayadd($dir, $path)
                        $dircount = $dircount + 1
    
                    case else
                    ;msgbox(0,"Found File:", $file)
                        filewriteline($hList, $path)
                endselect
            
            $file = filefindnextfile($hDir)
        wend
    endif
    
    fileclose($hDir)
    $x = $x + 1
wend

fileclose($hList)



;------------------------------------------------------------
func isDir($chkDir)
    if (stringinstr(filegetattrib($chkDir),"D")) then
        return 1
    else
        return 0
    endif
endfunc

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  
Followers 0