Extending FileSet - advanced file filtering

0 votes
asked Apr 23, 2013 by Rebex KB (8,130 points)
edited Apr 23, 2013

How to filter files using custom criteria? E.g. regular expression?

2 Answers

0 votes
answered Apr 23, 2013 by Rebex KB (8,130 points)
edited Apr 23, 2013

To use custom filter criteria in FileSet derive from it and implement IsMatch method yourself. Then use the derived class instead of the FileSet. E.g.

Ftp client = new Ftp();
// connect, login, ...

// download files using MyFileSet
MyFileSet set = new MyFileSet("/data", @"^data[0-9]+\.txt$");
client.Download(set, @"C:\data");

Here is a sample code for filtering using Regex:

/// <summary>
/// Matches files in BasePath directory (no subdirectory is processed) 
/// defined by a regular expression.
/// </summary>
public class MyFileSet : FileSet
{
    string _regexPattern;

    public MyFileSet(string basePath, string regexPattern)
        : base(basePath)
    {
        _regexPattern = regexPattern;
    }

    public override bool IsMatch(string relativePath, FileSetMatchMode mode)
    {
        // implement behavior for each match mode
        switch (mode)
        {
            case FileSetMatchMode.MatchFile:
                // take IsCaseSensitive into consideration
                RegexOptions options = RegexOptions.None;
                if (!IsCaseSensitive)
                    options = RegexOptions.IgnoreCase;

                // include files matching the specified pattern
                return Regex.IsMatch(relativePath, _regexPattern, options);

            case FileSetMatchMode.MatchDirectory:
                // don't match any directories (only files)
                return false;

            case FileSetMatchMode.TraverseDirectory:
                // traverse only current directory
                return relativePath == ".";

            default:
                throw new ArgumentOutOfRangeException("mode");
        }
    }
}

Please note, that this performs only SHALLOW SEARCH (no subdirectories are traversed). It is because in "case FileSetMatchMode.TraverseDirectory:" true is returned only for "." path (current directory). To perform DEEP SEARCH (traverse also subdirectories) update the class as follows:

case FileSetMatchMode.TraverseDirectory:
    // traverse all directories and subdirectories
    return true;

But please note, that this can be very time consuming. You should traverse only "meaningful" directories, however it depends on your application what "meaningful" means.

IMPLEMENTATION NOTE: for optimization issues when IsMatch is called with parameters equal to "." and FileSetMatchMode.TraverseDirectory the method should return false if no inclusion pattern was specified; true otherwise.
It means that if you return false always, current directory will not be traverses and no file or directory will be matched at all.

0 votes
answered Apr 23, 2013 by Rebex KB (8,130 points)
edited Apr 23, 2013

VB.NET version of the MyFileSet class:

''' <summary>
''' Matches files in BasePath directory (no subdirectory is processed) 
''' defined by a regular expression.
''' </summary>
Public Class MyFileSet
    Inherits FileSet

    Dim _regexPattern As String

    Public Sub New(ByVal basePath As String, ByVal regexPattern As String)
        MyBase.New(basePath)

        _regexPattern = regexPattern
    End Sub

    Public Overrides Function IsMatch(relativePath As String, mode As FileSetMatchMode) As Boolean
        ''# implement behavior for each match mode
        Select Case mode
            Case FileSetMatchMode.MatchFile
                ''# take IsCaseSensitive into consideration
                Dim options = RegexOptions.None
                If Not IsCaseSensitive Then options = RegexOptions.IgnoreCase

                ''# include files matching the specified pattern
                Return Regex.IsMatch(relativePath, _regexPattern, options)

            Case FileSetMatchMode.MatchDirectory
                ' don't match any directories (only files)
                Return False

            Case FileSetMatchMode.TraverseDirectory
                ''# traverse only current directory
                Return relativePath = "."

            Case Else
                Throw New ArgumentOutOfRangeException("mode")
        End Select
    End Function
End Class
...