DarkW1nter
DarkW1nter

Reputation: 2861

get files from directory based on substring of filename - C#

I have a C# console app which gets all files in a directory. Taking the file name below as an example, and given that I will have 3 strings, ref, year1, year2, how could I say:

File name: 31596_2015-06-30.pdf

Give me all files where the file name contain ref AND file name contains a year between year1 and year 2? Code so far:

var files = Directory.EnumerateFiles(sourceDir, "*", SearchOption.TopDirectoryOnly)
                          .Select(Path.GetFileName);

string start_year = null;
string end_year = null;
string ref = null;

// dr is a sql data reader
if (dr.HasRows == true)
{
    while (dr.Read())
    {
        start_year = dr.GetString(1).Substring(7, 4);
        end_year = dr.GetString(2).Substring(7, 4);
        ref = dr.GetString(3);

        foreach(string filename in files)
        {
            if (filename.Contains(ref)) 
            {
                File.Copy(sourceDir + filename, targetDir + filename);
            }
        }

        File.Copy(sourceDir + dr.GetString(0), targetDir + dr.GetString(0));
    }
}

Upvotes: 2

Views: 751

Answers (3)

Mong Zhu
Mong Zhu

Reputation: 23732

Assuming that your filenames have always the format as in your post, you first need to split the year out of the name. One possible solution could be:

 string filenameYear = filename.Split('_')[1].Split('-')[0];

then you can use this string in your if condition to ask for all three cases:

if (filename.Contains(_ref) &&
    Convert.ToInt32(filenameYear) > Convert.ToInt32(start_year) &&
    Convert.ToInt32(filenameYear) < Convert.ToInt32(end_year))
{
    // Do what ever you desire

}

in the line:

File.Copy(sourceDir + filename, targetDir + filename);

If sourceDir and targetDir has not a \ in the end or filename in the beginning. This will crash. You can use

File.Copy(Path.Combine(sourceDir,filename), Path.combine(targetDir, filename);

to avoid problems

ps. you should avoid using ref as a name for variables in C#. it is reserved as a keyword

Upvotes: 2

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186823

I suggest extracting a class, say, FileData:

public class FileData {
  public bool IsParsed {get; private set; }

  public String FileName {get; private set; }

  public DateTime Date {get; private set; }

  public String Ref {get; private set; }

  public FileData(String path) {
    FileName = path;

    if (String.IsNullOrEmpty(path))
      return;

    int p = path.IndexOf('_');

    if (p < 0)
      return;

    Ref = path.Substring(0, p);

    DateTime dt;

    IsParsed = DateTime.TryParseExact(path.Substring(p + 1), 
      "yyyy-MM-dd", 
      CultureInfo.InvariantCulture, 
      DateTimeStyles.None, 
     out dt);

    Date = dt;
  }
}

By doing this you can put a simple Linq to obtain the files

  var files = Directory
    .EnumerateFiles(sourceDir, "*", SearchOption.TopDirectoryOnly)
    .Select(file => new FileData(file))
    .Where(info => info.IsParsed)
    .Where(info => String.Equals(info.Ref, myRef))
    .Where(info => info.Date.Year >= year1 && info.Date.Year <= year2)
    .Select(info => info.FileName);

Upvotes: 3

Dave Kingston
Dave Kingston

Reputation: 56

I like Linq for this sort of thing. Unless you know for a fact that the values in the reader will always by what you expect, you should perform some validations, but this will achieve your stated goal with the least amount of changes to your sample code.

    var start_year = (DateTime)dr.GetString(1).Substring(7, 4);
    var end_year = (DateTime)dr.GetString(2).Substring(7, 4);
    ref = dr.GetString(3);

    foreach(string filename in files.Where(x => x.StartsWith(ref) 
                    && (DateTime)x.Substring(7, 4) >= start_year 
                    && (DateTime)x.Substring(7, 4) <= end_year))
    {
        File.Copy(sourceDir + filename, targetDir + filename);
    }

Upvotes: 1

Related Questions