如何配置 CsvHelper 以跳过 MissingFieldFound 行

问题描述 投票:0回答:6
public interface ICsvProductReaderConfigurationFactory
{
    Configuration Build();
}

public class CsvProductReaderConfigurationFactory : ICsvProductReaderConfigurationFactory
{
    private readonly ClassMap<ProductDto> classMap;

    public CsvProductReaderConfigurationFactory(IProductDtoClassMapProvider classMapProvider)
    {
        classMap = classMapProvider.Get();
    }

    public Configuration Build()
    {
        var config = new Configuration
        {
            Delimiter = "\t",
            HasHeaderRecord = true,
            IgnoreQuotes = true,
            MissingFieldFound = (rows, fieldIndex, readingContext) =>
                Log.Warn($"Missing Field Found at line {readingContext.Row}\r\n" +
                         $"Field at index {fieldIndex} does not exist\r\n" +
                         $"Raw record: {readingContext.RawRecord}"),
            BadDataFound = context => 
                Log.Warn($"Bad data found at row {context.Row}\r\n" +
                         $"Raw data: {context.RawRecord}")
        };

        config.RegisterClassMap(classMap);
        return config;
    }
}


public interface ICvsProductReader
{
    IEnumerable<ProductDto> GetAll(string filePath);
}

public class CvsProductReader : ICvsProductReader
{
    private readonly ICsvProductReaderConfigurationFactory csvProductReaderConfigurationFactory;

    public CvsProductReader(ICsvProductReaderConfigurationFactory csvProductReaderConfigurationFactory)
    {
        this.csvProductReaderConfigurationFactory = csvProductReaderConfigurationFactory;
    }

    public IEnumerable<ProductDto> GetAll(string filePath)
    {
        var csvReaderConfiguration = csvProductReaderConfigurationFactory.Build();

        using (var streamReader = new StreamReader(filePath))
        using (var csvReader = new CsvReader(streamReader, csvReaderConfiguration))
        {
            return csvReader.GetRecords<ProductDto>().ToArray();
        }
    }
}

MissingFieldFound
属性在发现缺失字段时被调用,但不会影响结果。

我想知道是否可以配置 CsvHelper 来跳过缺少字段的行。

c# csv csvhelper
6个回答
14
投票

你的做法没有任何问题,这是一个显示完整示例的 mcve

var good = new List<Test>();
var bad = new List<string>();

using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
    writer.WriteLine("FirstName,LastName");
    writer.WriteLine("\"Jon\"hn\"\",\"Doe\"");
    writer.WriteLine("\"JaneDoe\"");
    writer.WriteLine("\"Jane\",\"Doe\"");
    writer.Flush();
    stream.Position = 0;

    var isRecordBad = false;

    csv.Configuration.BadDataFound = context =>
    {
        isRecordBad = true;
        bad.Add(context.RawRecord);
    };

    csv.Configuration.MissingFieldFound = (headerNames, index, context) =>
    {
        isRecordBad = true;
        bad.Add(context.RawRecord);
    };

    while (csv.Read())
    {
        var record = csv.GetRecord<Test>();
        if (!isRecordBad)
        {
            good.Add(record);
        }

        isRecordBad = false;
    }
}

good.Dump();
bad.Dump();

9
投票

您还可以使用属性配置缺失的字段

[Optional]
Public string Field {get; set;}

[Ignore]
public int Filed {get; set;}

8
投票

使用我拥有的新版本 csvhelper (24.0.1),以下代码将用于设置

MissingFieldFound

Dim textReader As TextReader = File.OpenText(filename)

Dim config = New CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)

        config.Delimiter = ","
        config.MissingFieldFound = Nothing
        config.TrimOptions = True
        config.HeaderValidated = Nothing

Dim csv = New CsvReader(textReader, config)

4
投票

跳过

MissingFieldFound
行的另一种方法是使用
ShouldSkipRecord
并将标头记录长度与行记录长度进行比较。

// Load header record if you haven't already (CsvDataReader loads it automatically).
csv.Read();
csv.ReadHeader();

// Then do this.
var expectedRecordLength = csv.Context.HeaderRecord.Length;
csv.Configuration.ShouldSkipRecord = rowRecord => rowRecord.Length != expectedRecordLength;

如果您无法控制读取代码(例如,将

CsvDataReader
SqlBulkCopy
一起使用时),这尤其有用。


3
投票

Abumoosa 的答案对我有用,只不过是在 VB 中。这是 csharp 中的等效项:

var config = new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture);    
config.MissingFieldFound = null;

using (var reader = new StreamReader("taskList.csv"))
using (var csv = new CsvReader(reader, config)) {
    csv.Read();
    csv.ReadHeader();
    while (csv.Read()){
       //get the record
    }

0
投票

在更高版本中,此设置将起作用:

var config = new CsvHelper.Configuration.CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)
{
  MissingFieldFound = () => {}
}

using (var reader = new StreamReader("taskList.csv"))
using (var csv = new CsvReader(reader, config)) {
    csv.Read();
    csv.ReadHeader();
    while (csv.Read()){
       //get the record
    }
© www.soinside.com 2019 - 2024. All rights reserved.