【问题标题】:Trying to query many text files in the same folder with linq尝试使用 linq 查询同一文件夹中的许多文本文件
【发布时间】:2015-10-12 10:21:29
【问题描述】:

我需要搜索一个包含 csv 文件的文件夹。我感兴趣的记录有 3 个字段:Rec、Country 和 Year。我的工作是搜索文件,看看是否有任何文件有超过一年的记录。在我到目前为止的代码下方:

// 从文件夹中获取每个单独的文件。

 string startFolder = @"C:\MyFileFolder\";
    System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
    IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles("*.*",
    System.IO.SearchOption.AllDirectories);
    var queryMatchingFiles =
            from file in fileList
            where (file.Extension == ".dat" || file.Extension == ".csv")
        select file;

然后我想出了这段代码来从每个文件中读取年份字段并找到年份计数大于 1 的那些(计数部分未成功实现)

public  void GetFileData(string filesname, char sep)
    {
    using (StreamReader reader = new StreamReader(filesname))
    {
        var recs = (from line in reader.Lines(sep.ToString())
            let parts = line.Split(sep)
             select       parts[2]);
            }

下面是一个示例文件:

 REC,IE,2014

 REC,DE,2014

 REC,FR,2015

现在我正在努力将这两个想法结合起来,在一个查询中解决我的问题。查询应列出记录超过一年的文件。

提前致谢

【问题讨论】:

    标签: c# linq csv


    【解决方案1】:

    类似的东西:

    string startFolder = @"C:\MyFileFolder\";
        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);
        IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles("*.*",
        System.IO.SearchOption.AllDirectories);
        var fileData =
                from file in fileList
                where (file.Extension == ".dat" || file.Extension == ".csv")
            select GetFileData(file, ',')
    ;
    
    public  string GetFileData(string filesname, char sep)
        {
           using (StreamReader reader = new StreamReader(filesname))
           {
            var recs = (from line in reader.Lines(sep.ToString())
                let parts = line.Split(sep)
                 select       parts[2]);
            var multipleyears = recs.Distinct().Count();
            if(multipleyears > 1)
            return filename;
            }
        }
    

    【讨论】:

    • 这并没有说明文件中超过一年。
    • 我的查询需要返回我拥有超过一年的文件的列表。大多数文件应该只包含一年
    • 感谢您的额外努力。这是我的问题的解决方案
    【解决方案2】:

    不在我的开发机器上,所以这可能无法“按原样”编译,但这是一个方向

    var lines = // file.readalllines();
    var years = from line in lines 
               let parts = line.Split(new [] {','})
               select       parts[2]);            
    var distinct_years = years.Distinct();
    if (distinct_years >1 )
        // this file has several years
    

    【讨论】:

    • 不用担心。一旦我可以访问 linqpad,我会清理它 :)
    【解决方案3】:

    “我的工作是搜索文件并查看是否有任何文件有记录 超过一年。”

    这指定您想要一个布尔结果,表明是否有任何文件具有这些记录。

    为了好玩,我会再扩展一点:

    我的工作是收集任何记录超过一年的文件。

    你快到了。让我们首先用文件中的记录声明一个类:

    public class MyRecord
    {
        public string Rec { get; set; }
        public string CountryCode { get; set; }
        public int Year { get; set; }
    }
    

    我将创建 FileInfo 类的扩展方法,该方法将读取文件并返回其中的 MyRecords 序列。

    扩展方法见MSDN Extension Methods (C# Programming Guide)

    public static class FileInfoExtension
    {
        public static IEnumerable<MyRecord> ReadMyRecords(this FileInfo file, char separator)
        {
            var records = new List<MyRecord>();
            using (var reader = new StreamReader(file.FullName))
            {
                var lineToProcess = reader.ReadLine();
                while (lineToProcess != null)
                {
                    var splitLines = lineToProcess.Split(new char[] { separator }, 3);
                    if (splitLines.Length < 3) throw new InvalidDataException();
                    var record = new MyRecord()
                    {
                        Rec = splitLines[0],
                        CountryCode = splitLines[1],
                        Year = Int32.Parse(splitLines[2]),
                    };
                    records.Add(record);
                    lineToProcess = reader.ReadLine();
                }
            }
            return records;
        }
    }
    

    我本可以使用字符串而不是 FileInfo,但恕我直言,字符串与文件名完全不同。

    在上面你可以写如下:

    string startFolder = @"C:\MyFileFolder\";
    var directoryInfo = new DirectoryInfo(startFolder);
    var allFiles = directoryInfo.EnumerateFiles("*.*", SearchOption.AllDirectories);
    var sequenceOfFileRecordCollections = allFiles.ReadMyRecords(',');
    

    所以现在每个文件都有一个文件中的 MyRecords 序列。你想知道哪些文件有超过一年,让我们在 FileInfoExtension 类中添加另一个扩展方法:

    public static bool IsMultiYear(this FileInfo file, char separator)
    {
        // read the file, only return true if there are any records,
        // and if any record has a different year than the first record
        var myRecords = file.ReadMyRecords(separator);
        if (myRecords.Any())
        {
            int firstYear = myRecords.First().Year;
            return myRecords.Any(record => record.Year != firstYear);
        }
        else
        {
            return false;
        }
    }
    

    一年以上的文件顺序为:

    allFiles.Where(file => file.IsMultiYear(',');
    

    将所有内容放在一行中:

    var allFilesWithMultiYear = new DirectoryInfo(@"C:\MyFileFolder\")
        .EnumerateFiles("*.*", SearchOption.AllDirectories)
        .Where(file => file.IsMultiYear(',');
    

    通过创建两个相当简单的扩展方法,您的问题变成了一个高度可读的语句。

    【讨论】:

      猜你喜欢
      • 2010-11-20
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-05
      • 2018-12-20
      相关资源
      最近更新 更多