Can i use regular expression for file names?

0 votes
asked Apr 9, 2011 by Gowtham (240 points)
edited Mar 13, 2012

How can we use regular expressions in GetFiles and PutFiles methods? Currently wildcards are only supported.

Applies to: Rebex SFTP, Rebex FTP/SSL
commented Apr 10, 2011 by Gowtham (240 points)
edited Apr 22, 2011

Please help me to solve this issue. I have one very urgent release and this appears as a show stopper for me.

2 Answers

+2 votes
answered Mar 13, 2012 by Lukas Matyska (56,130 points)
edited Mar 13, 2012
 
Best answer

In the Release 2012 R1 the Rebex.IO.FileSet class was introduced. It can be used in all multi-file methods which are: Upload, Download, Delete and GetItems.

The Rebex.IO.FileSet class uses wildcards, but you can implement your own descendants to support regular expressions. It can be done as follows:

/// <summary>
/// FileSet matches files under BasePath (and all subdirectories) specified by a Regex.
/// </summary>
public class SimpleFileSet_DeepFileRegexMatch : FileSet
{
    string _includePattern;

    public SimpleFileSet_DeepFileRegexMatch(string basePath, string includePattern)
        : base(basePath)
    {
        _includePattern = includePattern;
    }

    public override bool IsMatch(string relativePath, FileSetMatchMode mode)
    {
        string filename = Path.GetFileName(relativePath);
        switch (mode)
        {
            case FileSetMatchMode.MatchFile:
                RegexOptions options = IsCaseSensitive ? 0 : RegexOptions.IgnoreCase;
                return Regex.IsMatch(filename, _includePattern, options);
            case FileSetMatchMode.MatchDirectory:
                return false;
            case FileSetMatchMode.TraverseDirectory:
                return true;
            default:
                throw new ArgumentOutOfRangeException("mode");
        }
    }
}

It can be used as follows:

// create set matching all .txt files under "C:/test1" directory
SimpleFileSet_DeepFileRegexMatch set = 
    new SimpleFileSet_DeepFileRegexMatch("C:/test1", "[.]txt$");

// print what the set matches
foreach (FileSystemItem item in set.GetLocalItems())
{
    Console.WriteLine(item.Path);
}

// prepare client for upload
Sftp client = new Sftp();
client.Connect(...);
client.Login(...);

// upload files according the set
client.Upload(set, "upload");

// set BasePath to the remote directory
set.BasePath = "upload";

// print what the set matches on the remote host
foreach (FileSystemItem item in client.GetItems(set))
{
    Console.WriteLine(item.Path);
}

// download matching files to local directory
client.Download(set, "C:/test2");
+1 vote
answered Apr 11, 2011 by Lukas Matyska (56,130 points)
edited Apr 11, 2011

Regular expressions are not supported in GetFiles/PutFiles methods, but it is a feature we are currently working on. It will be added in new release.

In the mean time you can use following simple implementation of GetFiles method which uses a regular expression to filter files/directories to be transferred.

Please leave a comment if you need a VB.NET code or if you want also the PutFiles method.

static void Main(string[] args)
{
    Ftp client = new Ftp();
    client.Connect(...);
    client.Login(...);

    GetFiles(client, "/data", @"c:\temp", new Regex("file[0-2].txt"), new Regex("dir(0|1)"));

    client.Disconnect();
}

private static void GetFiles(Ftp client, string remotePath, string localPath, Regex fileNameFilter, Regex directoryNameFilter)
{
    List<string> list = GetListRecursive(client, remotePath, fileNameFilter, directoryNameFilter);

    foreach (string remote in list)
    {
        string local = Path.Combine(localPath, GetRelativePath(remote, remotePath));
        string localDirectory = Path.GetDirectoryName(local);

        if (!Directory.Exists(localDirectory))
            Directory.CreateDirectory(localDirectory);

        client.GetFile(remote, local);
    }
}

private static List<string> GetListRecursive(Ftp client, string remotePath, Regex fileNameFilter, Regex directoryNameFilter)
{
    List<string> paths = new List<string>();

    client.ChangeDirectory(remotePath);

    FtpList list = client.GetList();
    foreach (FtpItem item in list)
    {
        string name = item.Name;
        string path = FtpPathCombine(remotePath, name);

        switch (item.Type)
        {
            case FtpItemType.Directory:
                if (directoryNameFilter.IsMatch(name))
                    paths.AddRange(GetListRecursive(client, path, fileNameFilter, directoryNameFilter));
                break;
            case FtpItemType.File:
                if (fileNameFilter.IsMatch(name))
                    paths.Add(path);
                break;
        }
    }

    return paths;
}

private static string FtpPathCombine(string path1, string path2)
{
    return string.Format("{0}/{1}", path1.TrimEnd('/'), path2.TrimStart('/'));
}

private static string GetRelativePath(string path, string basePath)
{
    return path.Substring(basePath.Length).TrimStart('/', '\\');
}
...