我正在尝试使用CsvHelper从CSV文件加载数据,以创建具有指定类型的数据列的数据表。
var textReader = new StreamReader(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{tableName}.csv"));
var csvReader = new CsvReader(textReader);
var csvDataReader = new CsvDataReader(csvReader);
var dataTable = new DataTable();
foreach(var column in metaColumns)
{
var dataColumn = new DataColumn(column.columnName, GetPropertyType(column.dataType));
dataColumn.AllowDBNull = column.isNull;
dataTable.Columns.Add(dataColumn);
}
dataTable.Load(csvDataReader);
在加载方法上,出现以下错误:
字符串''无法识别为有效的DateTime。无法将<>存储在 派生的_mdd_date列。预期的类型是DateTime。
显然,CsvHelper从CSV文件中将列作为空字符串加载,然后在给定DateTime类型时,并未将空字符串转换为空值。
经过研究并尝试添加的内容
csvReader.Configuration.TypeConverterOptionsCache.GetOptions<DateTime>().NullValues.Add("null");
csvReader.Configuration.TypeConverterOptionsCache.GetOptions<DateTime?>().NullValues.Add("null");
csvReader.Configuration.TypeConverterOptionsCache.GetOptions<string>().NullValues.Add("null");
csvReader.Configuration.TypeConverterCache.AddConverter<DateTime>(new DateFieldConverter());
csvReader.Configuration.TypeConverterCache.AddConverter<DateTime?>(new DateFieldConverter());
...
public class DateFieldConverter : DateTimeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
bool result = DateTime.TryParse(text, out DateTime ret);
if (result) return ret;
return null;
}
}
仍然出现相同的错误。我在DateFieldConverter上放置了一个断点,它从未被击中,因此某些内容无法正确同步。我认为DateTime列的默认行为将是DateTime.MinValue或null,但是它只是抛出错误。
答案 0 :(得分:0)
不幸的是,看起来CsvDataReader
会将所有值都视为字符串,而忽略了其他类型的TypeConverters。似乎有一个feature request添加了该功能。
我可以提供一种可能对您有用的解决方法。您可能还会检查我的answer here是否有其他选择。
public static void Main(string[] args)
{
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader))
{
writer.WriteLine("DateTime,DateTimeNullable");
writer.WriteLine("5/4/2019,");
writer.WriteLine(",5/5/2019");
writer.Flush();
stream.Position = 0;
csv.Configuration.TypeConverterCache.AddConverter<DateTime>(new DateFieldConverter());
csv.Configuration.TypeConverterCache.AddConverter<DateTime?>(new DateFieldNullableConverter());
var dataTable = new DataTable();
dataTable.Columns.Add("DateTime", typeof(DateTime)).AllowDBNull = false;
dataTable.Columns.Add("DateTimeNullable", typeof(DateTime)).AllowDBNull = true;
csv.Read();
csv.ReadHeader();
while (csv.Read())
{
var row = dataTable.NewRow();
foreach (DataColumn column in dataTable.Columns)
{
if (column.DataType == typeof(DateTime) && column.AllowDBNull)
{
row[column.ColumnName] = csv.GetField(typeof(DateTime?), column.ColumnName);
}
else
{
row[column.ColumnName] = csv.GetField(column.DataType, column.ColumnName);
}
}
dataTable.Rows.Add(row);
}
}
}
public class DateFieldConverter : DateTimeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if (text == string.Empty)
{
return DateTime.MinValue;
}
return base.ConvertFromString(text, row, memberMapData);
}
}
public class DateFieldNullableConverter : DateTimeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if (text == string.Empty)
{
return DBNull.Value;
}
return base.ConvertFromString(text, row, memberMapData);
}
}