Jump to content

UDF: _FileGetTreeList, _FileFindAllR


blindwig
 Share

Recommended Posts

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

Link to comment
Share on other sites

  • 1 month later...

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

Link to comment
Share on other sites

  • 4 months later...

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?

Link to comment
Share on other sites

  • 3 weeks later...

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...