Sign in to follow this  
Followers 0
blindwig

UDF: Filter file(s) by attributes

4 posts in this topic

I started out writing a UDF that would return a list of all files in a specified folder, in an array that could be handled by the Array standard UDF. Then, I wanted to specify a mask to match. Easy enough. Then, I wanted to filter the files by their attributes - for example, only return files (not folders) or don't return hidden files, or only return archive-flagged files, etc.

So, first I started by writing a file-filter routine, that takes a file and a filter string and returns true or false based on weather the file matches the filter:

Func _FileFilterAttrib($FileName, $Attrib)
    Dim $Return=0, $FileAttrib, $i, $ch
    If FileExists($FileName) Then
        $Return=-1
        $FileAttrib = FileGetAttrib($FileName)
        For $i = 1 to StringLen($Attrib)
            $ch = StringMid($Attrib,$i,1)
            If StringIsUpper($ch) Then
            ;This attribute must be on the list
                If not StringInStr($FileAttrib, $ch) then $Return = 0
            Else
            ;This attribute must not be on the list
                If StringInStr($FileAttrib, StringUpper($ch)) then $Return = 0
            EndIf
        Next
    EndIf
    Return $Return
EndFunc

The way the filter works is this:

It is a string of characters, the same of which are returned by the function FileGetAttribute

If a character is uppercase, then the file MUST hast this attribute to pass the filter, and if the character is lower-case then the file must NOT have this attribute to pass the filter.

For example, the default filter 'dhs' will only return true on files that are not directory, hidden, or system flagged. The filter 'D' would only return directories, and the filter 'Dh' would return directories that are not hidden.

The next step is to wrap this in a file searching routine, that would search an entire folder, first matching based on a filename mask, then filter by attributes:

Func _FileFindAll($Path, $Mask="*", $AttribFilter='dhs')
    Dim $FileList[100], $FileListSize = 0, $hndFile_Search, $CurFile
    If FileIsDir($Path) Then;Path exists and is a directory
        $hndFile_Search = FileFindFirstFile($Path & '\' & $Mask)
        If $hndFile_Search<>-1 Then; at least 1 file/directory exists
            $CurFile = FileFindNextFile($hndFile_Search)
            While not @error;loop through found files
                If FileFilterAttrib($Path & '\' & $CurFile, $AttribFilter) Then;file passes attribute filter
                    $FileListSize = $FileListSize + 1
                    If $FileListSize > UBound($FileList) Then ReDim $FileList[$FileListSize+20];increase list size
                    $FileList[$FileListSize - 1] = $CurFile
                EndIf
                $CurFile = FileFindNextFile($hndFile_Search)
            WEnd
            FileClose($hndFile_Search)
            ReDim $FileList[$FileListSize]
            Return $FileList
        EndIf
    EndIf
    Return 0
EndFunc

Calling it is pretty self-explanitory, I think:

_FileFindAll('C:\Windows','*.exe','dhs')

returns an array where [0]=number of results, and [1]...[x] are the file names.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

I started out writing a UDF that would return a list of all files in a specified folder, in an array that could be handled by the Array standard UDF.  Then, I wanted to specify a mask to match.  Easy enough.  Then, I wanted to filter the files by their attributes - for example, only return files (not folders) or don't return hidden files, or only return archive-flagged files, etc.

So, first I started by writing a file-filter routine, that takes a file and a filter string and returns true or false based on weather the file matches the filter:

Func _FileFilterAttrib($FileName, $Attrib)
    Dim $Return=0, $FileAttrib, $i, $ch
    If FileExists($FileName) Then
        $Return=-1
        $FileAttrib = FileGetAttrib($FileName)
        For $i = 1 to StringLen($Attrib)
            $ch = StringMid($Attrib,$i,1)
            If StringIsUpper($ch) Then
            ;This attribute must be on the list
                If not StringInStr($FileAttrib, $ch) then $Return = 0
            Else
            ;This attribute must not be on the list
                If StringInStr($FileAttrib, StringUpper($ch)) then $Return = 0
            EndIf
        Next
    EndIf
    Return $Return
EndFunc

The way the filter works is this:

It is a string of characters, the same of which are returned by the function FileGetAttribute

If a character is uppercase, then the file MUST hast this attribute to pass the filter, and if the character is lower-case then the file must NOT have this attribute to pass the filter.

For example, the default filter 'dhs' will only return true on files that are not directory, hidden, or system flagged.  The filter 'D' would only return directories, and the filter 'Dh' would return directories that are not hidden.

The next step is to wrap this in a file searching routine, that would search an entire folder, first matching based on a filename mask, then filter by attributes:

Func _FileFindAll($Path, $Mask="*", $AttribFilter='dhs')
    Dim $FileList[100], $FileListSize = 0, $hndFile_Search, $CurFile
    If FileIsDir($Path) Then;Path exists and is a directory
        $hndFile_Search = FileFindFirstFile($Path & '\' & $Mask)
        If $hndFile_Search<>-1 Then; at least 1 file/directory exists
            $CurFile = FileFindNextFile($hndFile_Search)
            While not @error;loop through found files
                If FileFilterAttrib($Path & '\' & $CurFile, $AttribFilter) Then;file passes attribute filter
                    $FileListSize = $FileListSize + 1
                    If $FileListSize > UBound($FileList) Then ReDim $FileList[$FileListSize+20];increase list size
                    $FileList[$FileListSize - 1] = $CurFile
                EndIf
                $CurFile = FileFindNextFile($hndFile_Search)
            WEnd
            FileClose($hndFile_Search)
            ReDim $FileList[$FileListSize]
            Return $FileList
        EndIf
    EndIf
    Return 0
EndFunc

Calling it is pretty self-explanitory, I think:

_FileFindAll('C:\Windows','*.exe','dhs')

returns an array where [0]=number of results, and [1]...[x] are the file names.

<{POST_SNAPBACK}>

Cool! :( These are very handy functions to have around.

Thanks. :(

-SolidSnake

Edited by SolidSnake

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites

It is pretty sad that I just found this post. Nice functions Blindwig.. :evil: I will have to add them to my listing of UDFs.

Cheers.. :)

Share this post


Link to post
Share on other sites

See also my _FileFindAllR() function, which uses the same principal and also searches recursively:

http://www.autoitscript.com/forum/index.php?showtopic=12835

Since that post I have come up with a better progress bar for the _FileGetTreeList() function - the one in that function is random because I couldn't think of a way to make a progress bar for an unknown number of items - but the code is not very portable as is. I had planned to re-write it and post it here, but have had other projects to work on and haven't had a chance to come back to it. It uses a recursive guessing method that doesn't always work out right (proportionally speaking) but is a lot better than just throwing random numbers out to try to make it look like I'm doing something useful :)

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