如何使用CsvHelper读取特定行的标题?

时间:2016-09-22 14:01:05

标签: c# .net csv csvhelper

我试图读取标题位于第3行的CSV文件:

some crap line
some empty line
COL1,COL2,COl3,...
val1,val2,val3
val1,val2,val3

如何告诉CSVHelper标题不在第一行?

我尝试使用Read()跳过2行,但是对ReadHeader()的后续调用会引发一个异常,即标题已被读取。

using (var csv = new CsvReader(new StreamReader(stream), csvConfiguration)) {
   csv.Read();
   csv.Read();
   csv.ReadHeader();
   .....

如果我将csvConfiguration.HasHeaderRecord设置为false ReadHeader()再次失败。

2 个答案:

答案 0 :(得分:4)

试试这个:

using (var reader = new StreamReader(stream)) {
      reader.ReadLine();
      reader.ReadLine();
      using (var csv = new CsvReader(reader)) {                    
          csv.ReadHeader();                    
    }
}

答案 1 :(得分:1)

这并不比Evk的答案好,但我很感兴趣。

CsvConfiguration类似乎有一个名为ShouldSkipRecord的Func回调,可以连接到它以实现自定义逻辑。

https://github.com/JoshClose/CsvHelper/tree/master/src/CsvHelper

CsvConfiguration.cs

/// <summary>
/// Gets or sets the callback that will be called to
/// determine whether to skip the given record or not.
/// This overrides the <see cref="SkipEmptyRecords"/> setting.
/// </summary>
public virtual Func<string[], bool> ShouldSkipRecord { get; set; }

CsvReader.cs

/// <summary>
/// Advances the reader to the next record.
/// If HasHeaderRecord is true (true by default), the first record of
/// the CSV file will be automatically read in as the header record
/// and the second record will be returned.
/// </summary>
/// <returns>True if there are more records, otherwise false.</returns>
public virtual bool Read()
{
    if (doneReading)
    {
        throw new CsvReaderException(DoneReadingExceptionMessage);
    }

    if (configuration.HasHeaderRecord && headerRecord == null)
    {
        ReadHeader();
    }

    do
    {
        currentRecord = parser.Read();
    }
    while (ShouldSkipRecord());

    currentIndex = -1;
    hasBeenRead = true;

    if (currentRecord == null)
    {
        doneReading = true;
    }

    return currentRecord != null;
}

/// <summary>
/// Checks if the current record should be skipped or not.
/// </summary>
/// <returns><c>true</c> if the current record should be skipped, <c>false</c> otherwise.</returns>
protected virtual bool ShouldSkipRecord()
{
    if (currentRecord == null)
    {
        return false;
    }

    return configuration.ShouldSkipRecord != null
        ? configuration.ShouldSkipRecord(currentRecord)
        : configuration.SkipEmptyRecords && IsRecordEmpty(false);
}

不幸的是,您似乎必须将HasHeaderRecord设置为false,然后在调用ReadHeaders或在第三行调用Read之前将其设置为true,因为Read()中的ShouldSkipRecord逻辑位于ReadHeader()逻辑。