Jump to content



Photo

UDF: _FileGetTreeList, _FileFindAllR


  • Please log in to reply
4 replies to this topic

#1 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 23 June 2005 - 10:55 PM

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








#2 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 28 July 2005 - 10:54 PM

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


#3 Freedom

Freedom

    Seeker

  • New Members
  • 5 posts

Posted 16 December 2005 - 09:51 AM

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?

#4 Freedom

Freedom

    Seeker

  • New Members
  • 5 posts

Posted 16 December 2005 - 10:04 AM

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!

#5 brandonm

brandonm

    Seeker

  • Active Members
  • 12 posts

Posted 02 January 2006 - 10:08 PM

Man, this rocks!
Just what I've been looking for for my ftp client!
Thanks!




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users