【问题标题】:Sorting file names in a directory giving wrongly ordered results对目录中的文件名进行排序会给出错误排序的结果
【发布时间】:2019-04-06 08:55:07
【问题描述】:

我在一个目录中有文件,文件名如下:

批处理 1.10.18.xlsx
批处理 2.10.18.xlsx
...
批处理 31.10.18.xlsx

如你所见,他们有这样的模式:Batch dd.mm.yy.xlsx

我需要按照文件名中这些日期的顺序处理它们。

到目前为止的代码:

private void processFiles(string BatchFilePath)
{
     IOrderedEnumerable<string> fileEntries = 
                Directory.GetFiles(BatchFilePath, "Batch *.xlsx")
                .OrderBy(f => GetFileDay(f));

     foreach (string fileName in fileEntries)
     {
        Console.WriteLine("Processing File " + Path.GetFileName(fileName));

        // Code that read and process files 
     }

}

private int GetFileDay(string file)
{
    string s1=  file.Substring(7, 2);
    if (s1.Substring(1) == ".")
        s1 = s1.Substring(0, 1);
     return int.Parse(s1);
}

代码不起作用。它仍然给我的文件名称顺序错误,如下所示:

批次 25.10.18.xlsx
批处理 22.10.18.xlsx...
批处理 9.10.18.xlsx
批处理 3.10.18.xlsx
...

【问题讨论】:

  • 向我们展示预期的订单和看到的订单
  • @John 我想“看到”的顺序是“批次 3.10.18”,然后是“批次 31.10.18”,然后是“批次 4.10.18”。
  • 我们可以假设您无法控制文件本身的命名吗?
  • 最佳答案也可能取决于文件的数量,这会阻止 UI 吗?
  • 谁知道排序是如此有趣! - 一些非常复杂的解决方案。我认为我的建议非常简单易懂 - 但这只是我自己的反映:-)

标签: c# linq directory


【解决方案1】:

将字符串(如“1.10.18”)解析为真实的DateTime(2018-10-01):

DateTime GetFileDay(string fileNameOrPath)
{
    string fileNameWithoutExt = System.IO.Path.GetFileNameWithoutExtension(fileNameOrPath);
    return DateTime.ParseExact(fileNameWithoutExt.Replace("Batch ", ""), "d.M.yy", null);
}

【讨论】:

  • 我认为好的答案不应该包含纯代码解决方案。你介意添加一些关于你的代码在做什么和为什么做的信息吗?
  • @vasily.sib 已编辑。
  • @skyoxZ 谢谢,你能不能把问题中的完整代码也加进去,让大家看看你是怎么使用GetFileDay 方法的?
【解决方案2】:

使用正则表达式从文件名中解析日期并根据日期时间排序。这是修改后的代码。

public static IOrderedEnumerable<string> GetFiles(string batchFilePath)
        {
            if (Directory.Exists(batchFilePath))
            {
                var directoryInfo = new DirectoryInfo(batchFilePath);
                var fileEntries = directoryInfo.GetFiles(@"Batch *.xlsx").Select(x => x.Name).OrderBy(f => GetFileDay(f));
                return fileEntries;
            }

            return null;
        }

    private static DateTime GetFileDay(string file)
    {
        var date = default(DateTime);
        var extractedDate = Regex.Match(file, @"(\W\S*(\d[\d]{0,2}))").Value;
        extractedDate = extractedDate.Replace(".", "-").Trim();           
        DateTime.TryParseExact(extractedDate, "d-MM-yy", CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out date);
        return date;
    }

【讨论】:

    【解决方案3】:

    考虑到您的文件集合将是 IEnumerable&lt;T&gt;,这将按您的文化的真实日期 [不是字符串!] 进行排序

    var l  = new List<string>()
    {
       "c:\\dev\\Batch 1.10.18.xlsx", 
       "c:\\dev\\Batch 2.10.18.xlsx", 
       "c:\\dev\\Batch 31.10.18.xlsx"
    };
    
    var ci = CultureInfo.GetCultureInfo("fr-FR"); // pick culture is same as pick format. You need to pre-define one
    var r = l.Select(x=>new{name = x, parts = Path.GetFileNameWithoutExtension(x).Split(" .".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)}).
            Select(a=> new {name = a.name, date = DateTime.Parse(a.parts[1] + "/" + a.parts[2] + "/" + a.parts[3], ci)}).
            OrderBy(x => x.date); //OrderByDescending(x => x.date);
    
    r.ToList().ForEach(x => Console.WriteLine(x.name));
    

    输出

    批处理 1.10.18.xlsx
    批处理 2.10.18.xlsx
    批处理 31.10.18.xlsx

    这可以更有效地完成,但线性度更低。

    【讨论】:

    • 这不是一些过度设计的解决方案吗?
    • @vasily.sib 它按日期排序,而不是日期的字符串表示。我可以选择 1 个选项,但为了举例,写起来会更长
    • 另一个答案也是按 DateTime 排序,但它不会为每个文件名实例化 2 个匿名对象,也不依赖于确切的文化:\
    • @vasily.sib 另一个答案也使用 2 个字符串搜索\解析方法并处理单个文件。虽然我的示例显示了 LINQ 的功能。那里提供了格式,好吗?如果每个答案都一样,生活会很无聊。我的回答是关于 linq、日期文化等,它不排序
    • var fileEntries = Directory.GetFiles(BatchFilePath, "Batch *.xlsx").OrderBy(GetFileDay); - 也是 LINQ。它只是使用私有方法而不是 lambda。
    【解决方案4】:

    您可以使用以下正则表达式。然后你可以在 Linq 上做 OrderBy/OrderByDescending:

    Regex r = new Regex(@"\d{1,2}.\d{1,2}.\d{2}");
    var orderByDateList = items.Where(po => r.IsMatch(po)).OrderByDescending(po => DateTime.ParseExact(r.Match(po).Value, "d.M.yy", null)).ToList(); // lines that match date pattern
    

    【讨论】:

    • 我认为你没有测试这个 :) d.M.yy - m 是分钟,而不是几个月。
    • 来吧伙计们。已经有一个基于DateTime.ParseExact() 的答案,为什么还要添加另一个?为什么这不仅仅是一条评论(“嘿,您也可以为此使用Regex”)?我是否应该添加另一个答案,即调用远程神经网络的 HTTP 请求,可以从字符串中提取日期?
    • @vasily.sib 好的,Vasya,你只是想控制每个人的想法、方法等。让 OP 选择他们喜欢的东西。让选民投票。各种各样的答案对 OP 来说是件好事,因为对于某人来说,整个新世界可能刚刚打开
    • @T.S.当然,我并不想控制任何人。我想要的是 SO 将专注于改进现有答案,而不是复制粘贴现有答案。
    • Gauravsa,对不起,如果我关于神经网络的例子看起来很粗糙,这只是我想到的另一个例子。
    猜你喜欢
    • 1970-01-01
    • 2020-07-30
    • 2018-07-25
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    相关资源
    最近更新 更多