Sign in to follow this  
Followers 0
blindwig

UDF: _FileGetTreeList, _FileFindAllR

5 posts in this topic

My function _FileGetTreeList is used to get the directory structure listed in an array, like doing a "dir /ad/s/b" and saving it to an array. This function can display a progress meter so you can see how far into the tree it is (also so you don't think it has frozen)

CODE

;===============================================================================

;

; Function Name: _FileGetTreeList

; Description: Returns a recursive list of directories

; Parameter(s): $Path = root path to begin the listing from

; $ProgressTitle = A title to put on a progress window. Empty String = no progress window

; Requirement(s): $Path is an existing directory

; Return Value(s): A 1-based array containing the full path of all found directories

; Note: Upon return, @Extended will contain a count of files (non-folders) found while searching for folders

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050622A

;

;===============================================================================

;

Func _FileGetTreeList($Path, $ProgressTitle = @ScriptName)

Dim $aDirList[100], $TotalFiles = 0

If $ProgressTitle <> '' Then ProgressOn($ProgressTitle, 'Scanning directories...', '', -1, -1, 16)

If _FileIsDir($Path) Then

$TotalFiles = __FileGetTreeList($aDirList, $Path, $ProgressTitle)

EndIf

If $ProgressTitle <> '' Then ProgressOff()

SetExtended($TotalFiles)

ReDim $aDirList[$aDirList[0]+1]

Return $aDirList

EndFunc

Func __FileGetTreeList(ByRef $aDirList, $Path, $ProgressTitle)

Dim $hndSearch_Dirs, $FileCount

If $ProgressTitle <> '' Then ProgressSet(random(99), $Path)

;Add the current directory on to the list

$aDirList[0] = $aDirList[0] + 1

If $aDirList[0] > UBound($aDirList) - 1 Then ReDim $aDirList[$aDirList[0] + 20]

$aDirList[$aDirList[0]] = $Path

;Scan for more directories

$hndSearch_Dirs = FileFindFirstFile($Path & '\*')

If $hndSearch_Dirs <> -1 Then

$sFileName = FileFindNextFile($hndSearch_Dirs)

While Not @error

If _FileIsDir($Path & '\' & $sFileName) Then

;Recurse into the directory, if it's not a special directory

If $sFileName <> '.' And $sFileName <> '..' Then

$FileCount = $FileCount + __FileGetTreeList($aDirList, $Path & '\' & $sFileName, $ProgressTitle)

EndIf

Else

;Add to the filecount

$FileCount = $FileCount + 1

EndIf

$sFileName = FileFindNextFile($hndSearch_Dirs)

WEnd

EndIf

FileClose($hndSearch_Dirs)

Return $FileCount

EndFunc

My _FileFindAllR function will return a list of files, found recursively, that match a given mask and attribute filter. This function also has an optional progress meter. The speed has been optimized by pre-fetching the directory structure and file count, so that these items don't have to be calculated dynamically.

CODE

;===============================================================================

;

; Function Name: _FileFindAllR

; Description: Returns a recursive list of files

; Parameter(s): $Path = root path to begin the listing from

; $Mask = file mask to match

; $AttribFilter = File Attributes to filter files through. See _FileFilterAttrib for details

; $ProgressTitle = A title to put on a progress window. Empty String = no progress window

; Requirement(s): $Path is an existing directory

; Return Value(s): A 1-based array containing the full path of all found files

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050622A

;

;===============================================================================

;

;Returns a recursive list of files under $Path, matching $Mask, and filtered through $AttribFilter

Func _FileFindAllR($Path, $Mask='*', $AttribFilter='dhs', $ProgressTitle = @ScriptName)

Dim $i, $aDirList = _FileGetTreeList($Path, $ProgressTitle), $FileList[@extended + 1]

If $ProgressTitle <> '' Then ProgressOn($ProgressTitle, 'Scanning files...', '', -1, -1, 16)

For $i = 1 to $aDirList[0]

If $ProgressTitle <> '' Then ProgressSet($i * 100 / $aDirList[0], $aDirList[$i])

__FileFindAllR($FileList, $aDirList[$i], $Mask, $AttribFilter)

Next

If $ProgressTitle <> '' Then ProgressOff()

ReDim $FileList[$FileList[0]+1]

Return $FileList

EndFunc

Func __FileFindAllR(ByRef $aFileList, $Path, $Mask, $AttribFilter)

Dim $hndSearch_Files

$hndSearch_Files = FileFindFirstFile($Path & '\' & $Mask)

If $hndSearch_Files <> -1 Then

$sFileName = FileFindNextFile($hndSearch_Files)

While Not @error

If _FileFilterAttrib($Path & '\' & $sFileName, $AttribFilter) And $sFileName <> '.' And $sFileName <> '..' Then

$aFileList[0] = $aFileList[0] + 1

$aFileList[$aFileList[0]] = $Path & '\' & $sFileName

EndIf

$sFileName = FileFindNextFile($hndSearch_Files)

WEnd

FileClose($hndSearch_Files)

EndIf

EndFunc

These functions require my _FileFilterAttrib function, and also my _FileIsDir function:

CODE

;===============================================================================

;

; Function Name: _FileIsDir

; Description: Returns true or false weather given file is a directory or not

; Parameter(s): $Path

; Requirement(s):

; Return Value(s): 0 = not a directory or does not exist, 1 = file exists and is a directory

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050623A

;

;===============================================================================

;

Func _FileIsDir($Path)

;This function checkes to see if $FileName exists and if it is a Directory

If StringInStr(FileGetAttrib($Path),'D') Then Return 1

Return 0

EndFunc

1 person likes this

Share this post


Link to post
Share on other sites



I rewrote the _FileGetTreeList() function. It now has a proper (meaningful) progress bar, and the array grows gemetrically instead of arithmetically, so the routine is a lot faster for large trees.

I use my _FileTruncPath() function, to display the paths as you go:

CODE

;Truncates $sPath so that its length is <= $iSize

Func _FileTruncPath($sPath, $iSize)

;split file from path

Local $iSplit = StringInStr($sPath, '\', 0, -1)

If $iSplit Then

$sFile = StringMid($sPath, $iSplit)

$sPath = StringLeft($sPath, $iSplit - 1)

Else

$sFile = $sPath

$sPath = ''

EndIf

;truncate and return new path

Local $iPath = StringLen($sPath), $iFile = StringLen($sFile)

If $iPath + $iFile <= $iSize Then

Return $sPath & $sFile

ElseIf $iFile > $iSize - 3 Then

Return '...' & StringRight($sFile, $iSize - 3)

Else

Return StringLeft($sPath, $iSize - 3 - $iFile) & '...' & $sFile

EndIf

EndFunc

And here's the new _FileGetTreeList() function:

CODE

;===============================================================================

;

; Function Name: _FileGetTreeList

; Description: Returns a recursive list of directories

; Parameter(s): $sPath = root path to begin the listing from

; $ProgressTitle = A title to put on a progress window. Empty String = no progress window

; Requirement(s): $sPath is an existing directory

; Return Value(s): A 1-based array containing the full path of all found directories

; Note: Upon return, @Extended will contain a count of all files and folders found while searching for folders

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050728A

;

;===============================================================================

;

Func _FileGetTreeList($sPath, $ProgressTitle = 'Mapping Directory Tree...')

Local $aDirList[100], $TotalFiles = 0

If $ProgressTitle <> '' Then _ProgressCreate ($ProgressTitle, '', @ScriptName)

If _FileIsDir($sPath) Then

If $ProgressTitle = '' Then

$TotalFiles = __FileGetTreeList($aDirList, $sPath, 0, 0)

Else

$TotalFiles = __FileGetTreeList($aDirList, $sPath, 0, 100)

EndIf

EndIf

If $ProgressTitle <> '' Then _ProgressDelete ()

SetExtended($TotalFiles)

ReDim $aDirList[$aDirList[0] + 1]

Return $aDirList

EndFunc ;==>_FileGetTreeList

Func __FileGetTreeList(ByRef $aDirList, $sPath, $ProCur, $ProMax)

If $ProMax > 0 Then _ProgressUpdate ($ProCur, _FileTruncPath($sPath, 60))

;Add the current directory to the global list

$aDirList[0] = $aDirList[0] + 1

If $aDirList[0] > UBound($aDirList) - 1 Then ReDim $aDirList[$aDirList[0] * 2]

$aDirList[$aDirList[0]] = $sPath

;Scan for more directories

Local $hndSearch_Dirs = FileFindFirstFile($sPath & '\*'), $FileCount, $aFolders[100]

If $hndSearch_Dirs <> - 1 Then

$sFileName = FileFindNextFile($hndSearch_Dirs)

While Not @error

;Add this entry to the total count

$FileCount = $FileCount + 1

;If this entry is a normal folder, add it to the local list

If _FileIsDir($sPath & '\' & $sFileName) And $sFileName <> '.' And $sFileName <> '..' Then

$aFolders[0] = $aFolders[0] + 1

If $aFolders[0] >= UBound($aFolders) Then ReDim $aFolders[$aFolders[0] * 2]

$aFolders[$aFolders[0]] = $sPath & '\' & $sFileName

EndIf

;look for the next entry

$sFileName = FileFindNextFile($hndSearch_Dirs)

WEnd

EndIf

FileClose($hndSearch_Dirs)

;Recurse into local folders

Local $i, $fSlice = $ProMax / $aFolders[0], $sProgress

For $i = 1 To $aFolders[0]

$FileCount = $FileCount + __FileGetTreeList($aDirList, $aFolders[$i], $ProCur + $fSlice * ($i - 1), $fSlice)

Next

Return $FileCount

EndFunc ;==>__FileGetTreeList

Share this post


Link to post
Share on other sites

WoW, blindwig you are my hero! This was just what I was looking for. Thx for funcs and keep up the good work. For some reason the code tags are not working properly. When I copy and past your script it just ends up on one line. Anyway to avoid this?

Share this post


Link to post
Share on other sites

I got the copy and past to work by first pasting into wordpad and then copying and pasting that into Scite followed by Tidy! Damn that was annoying!

Share this post


Link to post
Share on other sites

Man, this rocks!

Just what I've been looking for for my ftp client!

Thanks!

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