【问题标题】:CsvHelper - Set the header row and data rowCsvHelper - 设置标题行和数据行
【发布时间】:2020-10-12 21:35:47
【问题描述】:

我有如下示例数据:

 1  This is a random line in the file
 2  
 3  SOURCE_ID|NAME|START_DATE|END_DATE|VALUE_1|VALUE_2
 4
 5  Another random line in the file
 6  
 7  
 8  
 9  
10  GILBER|FRED|2019-JAN-01|2019-JAN-31|ABC|DEF
11  ALEF|ABC|2019-FEB-01|2019-AUG-31|FBC|DGF
12  GILBER|FRED|2019-JAN-01|2019-JAN-31|ABC|TEF
13  FLBER|RED|2019-JUN-01|2019-JUL-31|AJC|DEH
14  GI|JOE|2020-APR-01|2020-DEC-31|GBC|DER

我无法保存对文件的更改。即,我不能在消费前操作/清理原始文件。任何操作都需要在内存中即时完成。但是如果文件很大怎么办(例如,我目前正在测试一些超过 5m 记录的文件)。

我正在使用CsvHelper

我已经参考了以下线程以获得指导:

CSVHelper to skip record before header

Better way to skip extraneous lines at the start?

How to read a header from a specific line with CsvHelper?

我想做的是:

  • 设置表头所在的行 = 3(我会知道表头在哪里)
  • 设置数据开始的行 = 10(我会知道数据从哪里开始)
  • 将数据加载到数据表中,显示到datagridview中

如果我需要在将其传递给 CsvHelper 之前执行流操作的组合,那么是否还要让我知道这是否是缺失的部分? (以及任何关于我如何在一个代码块下实际实现这一点的帮助,不胜感激)

到目前为止,我想出了以下内容:

string filepath = Path.Combine(txtTst04_File_Location.Text, txtTst04_File_Name.Text);

using (var reader = new StreamReader(filepath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{

    // skip rows to get the header
    for (int i = 0; i < 4; i++) 
    {
        csv.Read();
    }

    csv.Configuration.Delimiter = "|"; // Set delimiter
    csv.Configuration.IgnoreBlankLines = false;
    csv.Configuration.HasHeaderRecord = true;
    
    // how do I set the row where the actual data starts? 

    using (var dr = new CsvDataReader(csv))
    {
        var dt = new DataTable();
        dt.Load(dr);
        dgvTst04_View.DataSource = dt; // Set datagridview source to datatable
    }

}

我得到以下结果:

如果您希望我在任何方面进行扩展,请告诉我。

谢谢!

编辑:

在此处创建的新链接帖子试图解决相同的目标,但方式不同但出现新错误: Filestream and datagridview memory issue with CsvHelper

【问题讨论】:

    标签: c# parsing csvhelper


    【解决方案1】:

    我可以让它与ShouldSkipRecord 一起工作。唯一的问题是,如果任何随机行带有“|”,它将失败分隔符。

    using (var reader = new StreamReader(filepath))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        csv.Configuration.Delimiter = "|"; // Set delimiter
        csv.Configuration.ShouldSkipRecord = row => row.Length == 1;
        
        using (var dr = new CsvDataReader(csv))
        {
            var dt = new DataTable();
            dt.Load(dr);
            dgvTst04_View.DataSource = dt; // Set datagridview source to datatable
        }
    
    }
    

    如果您知道有多少列,则可以将其设置为跳过任何列少于该列数的行。

    csv.Configuration.ShouldSkipRecord = row => row.Length < 6;
    

    【讨论】:

    • 谢谢@David。我也可以复制你的结果,它确实有效!我不知道列数,它将是动态的并且可以更改。 (用户也输入了标题行和数据行,剩下的应该由程序完成)。但是,我担心除标题和数据之外的行中是否使用任何分隔符。有没有其他方法可以解决它,特别是因为我们将确切地知道用于标题和数据的行?非常感谢您的帮助。
    • 我已将 David 的回复标记为答案(因为它在技术上确实有效),但我根据 Kiril 的评论添加了一个新帖子(我在原始帖子中添加了一个链接)
    【解决方案2】:

    我想出了另一种方法,它允许您跳过行到标题,然后到记录。

    using (var reader = new StreamReader(filepath))
    using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
    {
        csv.Configuration.Delimiter = "|"; // Set delimiter
        csv.Configuration.IgnoreBlankLines = false;
    
        // skip to header
        for (int i = 0; i < 3; i++)
        {
            csv.Read();
        }
    
        csv.ReadHeader();
    
        var headers = csv.Context.HeaderRecord;
    
        // skip to records
        for (int i = 0; i < 6; i++)
        {
            csv.Read();
        }
    
        var dt = new DataTable();
    
        foreach (var header in headers)
        {
            dt.Columns.Add(header);
        }
    
        while (csv.Read())
        {
            var row = dt.NewRow();
            for (int i = 0; i < headers.Length; i++)
            {
                row[i] = csv.GetField(i);
            }
    
            dt.Rows.Add(row);
        }
    }
    

    【讨论】:

    • 谢谢大卫,我会试一试并比较性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多