Jump to content

[SOLVED] Only specific 'level' folders using _FileListToArrayRec?


jantograaf
 Share

Recommended Posts

Hi all, 

I'm trying to make a listing of all files in subdirectories on a specific level in a folder structure. Let me explain, visually, this will help things a lot.

I have a folder structure like this:
 

ROOT
|--- SUBDIR 1
|      |---- SUBDIR 1.1
|               |----- SUBDIR 1.1.1
|                          |---- File1.ext
|               |----- SUBDIR 1.1.2
|                          |---- File2.ext
|               |----- SUBDIR 1.1.3
|                          |---- File2.ext
|               |----- SUBDIR 1.1.4
|                          |---- File2.ext
|               |----- SUBDIR 1.1.5
|                          |---- File2.ext
|      |---- SUBDIR 1.2
|               |----- SUBDIR 1.2.1
|                   .....
|      |---- SUBDIR 1.3
                    ....

I use _FileListToArrayRec twice:
- once to make an array of the specific directories I should be working at: I need all files on the x.x level, so it will go just until that depth using a negative integer for $iRecur
- once again to create an array of all files found under that directory and its subdirectories (level x.x.x\files...)

What happens now is that _FileListToArrayRec will always include all levels before the maximum depth is reached. The result would look like this

Row 0   15
Row 1   Root\Subdir 1
Row 2   Root\Subdir 2
Row 3   Root\Subdir 3
Row 4   Root\Subdir 1\Subdir 1.1
Row 5   Root\Subdir 1\Subdir 1.2
Row 6   Root\Subdir 1\Subdir 1.3
...

Needless to say that when my second function iterates over this array, it will find all files twice. Once on the x level, once again on the x.x level. There is no way for me not to use the recursive option in the second iteration, since the files are actually in a subdirectory there.

Where are the wizards of programming logic here? Since I can't seem to find a comprehensible or easily implementable solution for this issue.

Thanks in advance and kind regards,

Jan

Edited by jantograaf
Link to comment
Share on other sites

Alright, I'm not marking this solved yet, but there might be a solution I just thought of.

Maybe I just need to do the first _FileListToArrayRec twice. Once on the level needed, once on a level just above that. And then write a little loop that searches and deletes all the lines of the second array from the first array? 🧐

Just thinking out loud here...

Link to comment
Share on other sites

Okay, so this solved the issue. Nevermind. Just keeping this here for reference so other people can see the solution I thought best 🙂

If $ArrayDepth <= -1 Then
    ;First we fill an array with all the folders one level up
    $LevelUpFolderArray = _FileListToArrayRec($DCMFolder,"*",$FLTAR_FOLDERS,$ArrayDepth + 1,$FLTAR_SORT,$FLTAR_FULLPATH)
    ;If this provides a result (it always should, since this is only run when the $FolderArray contains any lines)
    If IsArray($LevelUpFolderArray) Then
        ;Using an DeleteCounter to keep track of the rows where we left off deleting
        ;Doing this since _BinarySearch did not work for me but the arrays ARE sorted
        Local $ArrayDeleteCounter = 0
        Local $FoundInRow = 0
        For $i = 1 To $LevelUpFolderArray[0]
            ;For each line in $LevelUpFolderArray, delete the corresponding line in $FolderArray
            $FoundInRow = _ArraySearch($FolderArray,$LevelUpFolderArray[$i],$ArrayDeleteCounter)
            If $FoundInRow > 0 Then
                ;Set the position to this found item
                $ArrayDeleteCounter = $FoundInRow
                ;Delete the row
                _ArrayDelete($FolderArray,$FoundInRow)
                ;Adjust the element count in the FolderArray
                $FolderArray[0] = $FolderArray[0] - 1
                ;Reset the FoundInRow-variable
                $FoundInRow = 0
            EndIf
        Next
    EndIf
EndIf

 

Edited by jantograaf
Included solution code...
Link to comment
Share on other sites

  • Developers

@jantograaf,

You could also build your own recursive UDF to get this done. Something like this should be close:

Func FindFilesAtLevel($filepath, $targetLevel = 0, $filemask = "", $level = 1)
    If StringRight($filepath, 1) <> "\" Then $filepath &= "\"
    Local $hSearch = FileFindFirstFile($filepath & "*.*")
    If $hSearch = -1 Then
        ; ConsoleWrite("No files/directories matched the search pattern:" & $filepath & "*.*" & @CRLF)
        Return False
    EndIf
    Local $sFileName = "", $iResult = 0
    While 1
        $sFileName = FileFindNextFile($hSearch)
        If @error Then ExitLoop

        ; directory found higher level -> go one level deeper
        If ($level < $targetLevel Or $targetLevel = 0) And StringInStr(FileGetAttrib($filepath & $sFileName), "D") Then
            FindFilesAtLevel($filepath & $sFileName, $targetLevel, $filemask, $level + 1)
        EndIf

        ; File found  at appropriate level -> do what needs to be done
        If ($level = $targetLevel Or $targetLevel = 0) And Not StringInStr(FileGetAttrib($filepath & $sFileName), "D") And StringRegExp($sFileName, $filemask) Then
            ConsoleWrite('@@ FileName = ' & $filepath & $sFileName & @CRLF) ;### Debug Console
        EndIf
    WEnd
    ; Close the search handle.
    FileClose($hSearch)
EndFunc   ;==>FindFilesAtLevel

Which could be used as follows:

ConsoleWrite("! Example 1: List all file in c:\temp and subdirectories" & @CRLF)
$FindRoot = "c:\temp"
FindFilesAtLevel($FindRoot)        ; List all files from FindRoot

ConsoleWrite("! Example 2: List all file in c:\temp\*\" & @CRLF)
$FindRoot = "c:\temp"
FindFilesAtLevel($FindRoot, 2)

ConsoleWrite("! Example 2b: List all files in c:\temp\*\*" & @CRLF)
$FindRoot = "c:\temp"
FindFilesAtLevel($FindRoot, 3)

ConsoleWrite("! Example 3: List all *.JPG files in c:\temp\ and subdirectories" & @CRLF)
$FindRoot = "c:\temp"
$FindFiles = ".?\.jpg"      ; RegEx filter, use "" for all files
FindFilesAtLevel($FindRoot, 0, $FindFiles)

ConsoleWrite("! Example 3b: List all *.JPG files in c:\temp\*\*" & @CRLF)
$FindRoot = "c:\temp"
$FindFiles = ".?\.jpg"      ; RegEx filter, use "" for all files
FindFilesAtLevel($FindRoot, 3, $FindFiles)

Example 2 is what you are looking for I guess. ;) 

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

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

×
×
  • Create New...