如何配置 CsvHelper 以跳过 MissingFieldFound 行
How to configure CsvHelper to skip MissingFieldFound rows
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 配置为跳过缺少字段的行。
你这样做没有错,这是一个显示完整示例的 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();
另一种跳过 MissingFieldFound
行的方法是使用 ShouldSkipRecord
并将 header 记录长度与行记录长度进行比较。
// 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
结合使用时),这将特别有用。
使用我拥有的新版 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)
您还可以使用属性配置缺失的字段
[可选]
Public 字符串字段 {get;设置;}
或
[忽略]
public int 归档 {get;设置;}
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 配置为跳过缺少字段的行。
你这样做没有错,这是一个显示完整示例的 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();
另一种跳过 MissingFieldFound
行的方法是使用 ShouldSkipRecord
并将 header 记录长度与行记录长度进行比较。
// 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
结合使用时),这将特别有用。
使用我拥有的新版 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)
您还可以使用属性配置缺失的字段
[可选]
Public 字符串字段 {get;设置;}
或
[忽略]
public int 归档 {get;设置;}