0

Now I have a directory with bunch files with format of name like "EXT2-401-B-140422-1540-1542.mp4", within which the "140422" part indicates the date. Now assume that this bunch of files have the dates like 140421, 140422, 140423...(for every date there are couple of files). Now I shall sort these files according to their dates, so I'd like to know how could I get these names (140421,140422,etc). I tried like this:

directory = new DirectoryInfo(camera_dir);    
string[] date = new string[directory.GetFiles().Length];
foreach (FileInfo file in directory.GetFiles())
{ 
    foreach(string name in date)
    {
        name = file.Name.Substring(11, 6);
    }
}

And the error message is that I can't assign to name. So anybody could help?

Rytis I
  • 1,105
  • 8
  • 19
jcraffael
  • 81
  • 3
  • 12
  • seems like a job for regex – Rytis I May 26 '14 at 10:20
  • possible duplicate of [Why can't we assign a foreach iteration variable, whereas we can completely modify it with an accessor?](http://stackoverflow.com/questions/7838079/why-cant-we-assign-a-foreach-iteration-variable-whereas-we-can-completely-modi) – Kilazur May 26 '14 at 10:20
  • Foreach variables are not allowed to store values. This is the reason that it is throwing the above specified error. – Robert Langdon May 26 '14 at 10:22

5 Answers5

5

You can use LINQ to simplify this a bit.

To get filenames only, you simply need to project each FileInfo into a string:

var dates = directory
    .EnumerateFiles("*.mp4")
    .Select(f => f.Name)
    .ToArray();

To get an ordered list, you also need to use OrderBy and specify the value to be used for ordering:

var dates = directory
    .EnumerateFiles("*.mp4")
    .Select(f => f.Name)
    .OrderBy(f => f.Substring(11, 6)) // this will throw if string is too short
    .ToArray();

You should also probably add some validation to prevent exceptions when filenames are not formatted properly. The least you can do is check if the string is long enough to have these 6 characters extracted:

var dates = directory
    .EnumerateFiles("*.mp4")
    .Select(f => f.Name)
    .Where(f => f.Length >= 17) // check if there are enough characters
    .OrderBy(f => f.Substring(11, 6))
    .ToArray();
vgru
  • 49,838
  • 16
  • 120
  • 201
  • Thank you for the cool method. I guess that makes sense(since I've no background of LINQ). I shall study more! :) – jcraffael May 26 '14 at 10:40
  • @jcraffael: I've updated the answer a bit to do some basic validation. – vgru May 26 '14 at 10:43
  • @Michael: yeah, that's the lazy `IEnumerable` version more suitable for LINQ queries. – vgru May 26 '14 at 10:43
  • 1
    That's the cleanest way to do it so far. – Kilazur May 26 '14 at 10:45
  • For portability I get why the validation is there but it seems that these files are built by a computer (camera) so maybe the validation is confusing the situation?.. However your solution is the fastest to execute and is by far the simplest. – Michael Coxon May 26 '14 at 10:48
  • 1
    @Michael: yeah, I also decided to remove that part from the answer to simplify it. – vgru May 26 '14 at 10:56
1

try this:

    var files = directory.GetFiles();
    string[] dates = new string[files.Length];
    for(int i = 0; i < files.Length; i++)
    { 
        dates[i] = files[i].Name.Substring(11, 6);
    }
Rytis I
  • 1,105
  • 8
  • 19
0

In fact you are asking two questions.

  1. You cannot assign a variable from the foreach. Create a new one to store the name in.

  2. For the second part, how to extract it: use this regex:

    string s = Regex.Replace(file.Name, @"(.*?)\-(.*?)\-(.*?)\-(.*?)\-(.*)", "$4");
    

    The ? makes the regex non-greedy, meaning that this expression will find the text after the third dash.

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
0
directory = new DirectoryInfo(camera_dir);    
string[] date = new string[directory.GetFiles().Length];
int i=0;
foreach (FileInfo file in directory.GetFiles())
{ 
    name[i] = file.Name.Substring(11, 6);
    i++;
}
Sultan
  • 319
  • 3
  • 11
0

I would be doing something like creating a class for the file name (if they are all the same structure) then splitting them out (apologies for reworking the entire code, also what the other guys are saying is something worth noting about foreach's not begin able to modify the set)...

public class MyFile 
{
    // EXT2-401-B-140422-1540-1542.mp4
    public string part1 { get; set;}
    public string part2 { get; set;}
    public string part3 { get; set;}
    public string date { get; set;}
    public string part5 { get; set;}
    public string part6 { get; set;}

    void MyFile(string fileName)
    {
        string[] parts = fileName.split('-');

        part1 = parts[0];
        part2 = parts[1];
        part3 = parts[2];
        date  = parts[3];
        part5 = parts[4];
        part6 = parts[5];
    }
}

then you can loop through...

directory = new DirectoryInfo(camera_dir);    

List<MyFile> myFiles = new List<MyFile>();

foreach (FileInfo file in directory.GetFiles())
{    
   myFiles.Add(new MyFile(file.Name));
}

Then you can sort, select, "blah" on any of the files using linq...

EDIT:

Additionally, if your previous code worked, you would end up with the date array being full of one date because you are trying to set the name (being each element in the array) to the current file name for the length of the array every single iteration of the directory.GetFiles() array.

Name the 'parts' something useful to you.

Michael Coxon
  • 5,311
  • 1
  • 24
  • 51
  • In this specific example, it's overkill and leads to unneeded use of memory and stuff I'm not competent enough to explain in a short comment. But I guess he will find use for the other parts someday, so it's still worth something :p – Kilazur May 26 '14 at 10:46
  • I fully get what you are saying, and you are right. I just provided this because I can see that the two 'fields' after the date are the timespan of the recording. If OP want them as well they would be much better off with a class instead of two arrays that stored date and time. Scope of the project is hard to determine from the question (and I may have broken protocol here :P) but I just wanted to be concise. – Michael Coxon May 26 '14 at 10:54
  • Yes exactly it happens that the date arrary is full of the same date. Fortunately I could handle that. I'm pretty sure your solution solves that problem perfectly but it's a bit hard...anyway thank you very much for the solution, probably this idea solves other tougher problem :) – jcraffael May 26 '14 at 14:32