CsvHelper - 在读取记录时执行逻辑
CsvHelper - Perform logic while reading records
我想在读取文件时应用逻辑,例如清理一串特殊字符,或者如果字段为空则确定两个日期之间的差异。
我已经在我的地图上试过了:
public InboundPlacementMap()
{
AutoMap();
Map(m => m.HomePhone).ConvertUsing(
rec =>
{
return CleanPhoneNumber(rec.HomePhone);
});
Map(m => m.LengthOfStay).Name("Length of Stay").ConvertUsing(
row =>
{
if (row.LengthOfStay > 0)
return (int)row.LengthOfStay;
return (row.AdmitDate - row.DischargeDate+500).Days;
});
}
private string CleanPhoneNumber(string phone)
{
//Do some logic to remove characters, etc.
return phone;
}
(实际上,CleanPhoneNumber 位于跨项目使用的不同库中。)但是调用它有一种我不喜欢的味道,而且它似乎不起作用:
Map(m => m.PatHomePhone).ConvertUsing(rec =>
{ return PamUtility.Utilities.CleanPhoneNumber(rec.PatHomePhone); });
在我阅读的方法中,我使用 GetRecords<>() 一次阅读所有内容。我最好逐条阅读记录,并在阅读每一条记录后执行我的逻辑吗? (这对我来说似乎很混乱。)
List<InboundPlacementFileRecord> allRecords = new List<InboundPlacementFileRecord>();
using (TextReader textReader = File.OpenText(fileToRead))
{
var csv = new CsvReader(textReader);
csv.Configuration.Delimiter = "|";
csv.Configuration.IgnoreBlankLines = true;
csv.Configuration.PrepareHeaderForMatch =
header => header.Replace(" ", string.Empty);
csv.Configuration.HeaderValidated= null;
csv.Configuration.MissingFieldFound = null;
csv.Configuration.RegisterClassMap<InboundPlacementMap>();
allRecords = csv.GetRecords<InboundPlacementFileRecord>().ToList();
}
编辑:
作为参考,这是逐个记录的样子,如果要执行更多逻辑,它会很快变得丑陋,因此我希望将其放入映射中:
while (csv.Read())
{
var record = csv.GetRecord<InboundPlacementFileRecord>();
record.LengthOfStay=(record.LengthOfStay>0)? record.LengthOfStay :
(int)(record.DischargeDate-record.AdmitDate).TotalDays;
// ... other logic here ...
allRecords.Add(record);
}
(在提出这个问题时使用最新的 CsvHelper,7.1.0。)
这真的是一个偏好问题。在映射中做所有事情都很好。在线执行也很好。替代 ConvertUsing
的另一种选择是创建自定义类型转换器。您可以使用其中一个内置的作为示例。 https://github.com/JoshClose/CsvHelper/blob/master/src/CsvHelper/TypeConversion/BooleanConverter.cs
GetRecords<T>()
returns 一个 IEnumerable<T>
将 yield
记录。这意味着它只会在每次迭代中提取一条记录,因此您不必担心所有数据都在内存中。如果你做类似ToList()
或Count()
的操作,它会将所有记录拉入内存,所以要小心。
我想在读取文件时应用逻辑,例如清理一串特殊字符,或者如果字段为空则确定两个日期之间的差异。
我已经在我的地图上试过了:
public InboundPlacementMap()
{
AutoMap();
Map(m => m.HomePhone).ConvertUsing(
rec =>
{
return CleanPhoneNumber(rec.HomePhone);
});
Map(m => m.LengthOfStay).Name("Length of Stay").ConvertUsing(
row =>
{
if (row.LengthOfStay > 0)
return (int)row.LengthOfStay;
return (row.AdmitDate - row.DischargeDate+500).Days;
});
}
private string CleanPhoneNumber(string phone)
{
//Do some logic to remove characters, etc.
return phone;
}
(实际上,CleanPhoneNumber 位于跨项目使用的不同库中。)但是调用它有一种我不喜欢的味道,而且它似乎不起作用:
Map(m => m.PatHomePhone).ConvertUsing(rec =>
{ return PamUtility.Utilities.CleanPhoneNumber(rec.PatHomePhone); });
在我阅读的方法中,我使用 GetRecords<>() 一次阅读所有内容。我最好逐条阅读记录,并在阅读每一条记录后执行我的逻辑吗? (这对我来说似乎很混乱。)
List<InboundPlacementFileRecord> allRecords = new List<InboundPlacementFileRecord>();
using (TextReader textReader = File.OpenText(fileToRead))
{
var csv = new CsvReader(textReader);
csv.Configuration.Delimiter = "|";
csv.Configuration.IgnoreBlankLines = true;
csv.Configuration.PrepareHeaderForMatch =
header => header.Replace(" ", string.Empty);
csv.Configuration.HeaderValidated= null;
csv.Configuration.MissingFieldFound = null;
csv.Configuration.RegisterClassMap<InboundPlacementMap>();
allRecords = csv.GetRecords<InboundPlacementFileRecord>().ToList();
}
编辑: 作为参考,这是逐个记录的样子,如果要执行更多逻辑,它会很快变得丑陋,因此我希望将其放入映射中:
while (csv.Read())
{
var record = csv.GetRecord<InboundPlacementFileRecord>();
record.LengthOfStay=(record.LengthOfStay>0)? record.LengthOfStay :
(int)(record.DischargeDate-record.AdmitDate).TotalDays;
// ... other logic here ...
allRecords.Add(record);
}
(在提出这个问题时使用最新的 CsvHelper,7.1.0。)
这真的是一个偏好问题。在映射中做所有事情都很好。在线执行也很好。替代 ConvertUsing
的另一种选择是创建自定义类型转换器。您可以使用其中一个内置的作为示例。 https://github.com/JoshClose/CsvHelper/blob/master/src/CsvHelper/TypeConversion/BooleanConverter.cs
GetRecords<T>()
returns 一个 IEnumerable<T>
将 yield
记录。这意味着它只会在每次迭代中提取一条记录,因此您不必担心所有数据都在内存中。如果你做类似ToList()
或Count()
的操作,它会将所有记录拉入内存,所以要小心。