LINQ GroupBy With FileNames

时间:2012-04-28 19:11:31

标签: c# linq

尝试在一组文件中获取不同标识符的集合。我对这个Lambda查询做错了什么:

   var enumDir = Directory.GetFiles(folder);
   var distinctCode = enumDir.Select(s => Path.GetFileName(s).Substring(8, 4))
                              .GroupBy(s => s.ToString());

提前致谢...

修改

@empi建议。我希望从文件名中得到一个不同的4个字母子字符串的列表,我得到的是什么,或者我首先将Path.Get ....部分放入组中,并且我得到了一个超出范围的索引异常。

@Oskar Kjellin建议我应该提到每个文件名的长度都是45个字符

最终解决方案|感谢empi和Oskar

var enumDir = Directory.GetFiles(folder).Where(a => Path.GetFileName(a).Length > 12);
var distinctCode = enumDir.Select(s => Path.GetFileName(s).Substring(8, 4)).Distinct();

真的是两种建议的组合,我不知道是谁真正标记答案。

4 个答案:

答案 0 :(得分:1)

在调用子字符串之前,您应该始终检查长度以避免异常......

 enumDir = Directory.GetFiles(folder);
 distinctCode = enumDir.Select(s => Path.GetFileName(s))
.Select( s=> s.Length >= 12 ? s.Substring(8, 4) : s).GroupBy(s => s);

您永远无法真正控制文件夹中的文件。例如,windows可以创建thumbs.db,它是图像或其他临时文件缩略图的缓存。

也许您只想过滤掉那些固定长度的人:

 enumDir = Directory.GetFiles(folder);
 distinctCode = enumDir.Select(s => Path.GetFileName(s)).Where(s=>s.Length == 45)
.Select( s=> s.Substring(8, 4)).GroupBy(s => s);

答案 1 :(得分:1)

enumDir.Select(s => Path.GetFileName(s).Substring(8, 4)) - 此代码应返回IEnumerable<string> - 检查此集合是否正常。如果没问题,那么只需使用Distinct()

答案 2 :(得分:1)

我怀疑你要找的是获取实际的文件名,但是用子串将它们分组。

var result = Directory.GetFiles(folder)
    .Select(s => Path.GetFileName(s))
    .Where(s => s.Length > 12)
    .GroupBy(s => s.Substring(8, 4));

现在在result中,您拥有Key作为子字符串的组对象,如果您枚举它们,则会获得与该键匹配的实际文件名。

答案 3 :(得分:1)

我认为使用正则表达式进行验证可以做得更好。您在查询中尝试执行的检查类型太复杂,无法在单个查询中执行。可能在该目录中可能存在其他文件,这些文件不符合您期望的模式,并且可能会弄乱所有内容。这种复杂性可以通过正则表达式来捕获。如果您的文件名遵循某种模式,那么简单的正则表达式匹配就可以为您处理。

我不知道你的文件名是怎么样的,所以我将以Windows Media Center的录制电视为例。所有WMC文件名都有一定的模式:

[title]_[station]_[year]_[month]_[day]_[hour]_[minute]_[second].wtv

然后按标题对所有视频进行分组,您可以这样做:

var dir = @"C:\Users\Public\Recorded TV";
var wmcFileRe = new Regex(@"
    ^
    (?<title>.+)
    _
    (?<station>.+)
    _
    (?<date>\d{4}_\d{2}_\d{2})
    _
    (?<time>\d{2}_\d{2}_\d{2})
    \.wtv
    $
", RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
var query =
    from filePath in Directory.EnumerateFiles(dir)
    let fileName = Path.GetFileName(filePath)
    let match = wmcFileRe.Match(fileName)
    where match.Success
    orderby match.Groups["title"].Value,
            match.Groups["date"].Value descending,
            match.Groups["time"].Value descending
    group filePath by match.Groups["title"].Value;

产生类似这样的东西:

example

另外,请使用Directory.EnumerateFiles()代替Directory.GetFiles(),这样您就不会预先创建该数组结果,而在其他任何地方都不需要该数组。