Csv Reader 可以根据列数使用不同的记录类型映射吗?
Can CsvReader use different Record Type Maps based upon column count?
我有一堆 CSV 文件需要阅读,除了添加了一列外,它们都很相似。本质上,旧的 CSV 格式有 7 列,而新的将有 8 列。没有 headers。读取后,新列将是 defaulted/edited,然后文件在写出时将有 8 列 - 因此以后的读取现在将具有新列。
所以我正在尝试做类似这个 CvsHelper 示例的事情:
Reading Multiple Record Types
唯一的区别在于文件中的列数 - 而不是标识字段值。
我在自己的 using() 中尝试了一个 CsvParser,并在文件的第一行中使用了一个 Read() 来确定列数,因为随后的 using() 中的 CsvReader 可以注册一个特定的计数ClassMap 为 CsvReader.GetRecords。但是,似乎没有 属性 或方法可以回答解析器遇到的列数。与 CsvReader.Read() 相同 - CsvReader.Context.ColumnCount 在 Read() 之后为零。任何想法/指示表示赞赏。
更新
这是我修改后的代码(长名称,我知道)- 感谢大卫的建议:
namespace TopazDomain.Classes
{
public class FootprintComponentMap : Entity<int>
{
private const int footprintWidth = 40;
[StringLength(footprintWidth)]
public string Footprint { get; set; }
private const int valueWidth = 40;
[StringLength(valueWidth)]
public string Value { get; set; }
public int Component { get; set; }
public int Head { get; set; }
private const int rotationWidth = 9;
[StringLength(rotationWidth)]
public string CompR { get; set; }
private const int polarizedWidth = 2;
[StringLength(polarizedWidth)]
public string Polarized { get; set; }
private const int commentWidth = 40;
public string Comment { get; set; }
[StringLength(rotationWidth)]
public string LibR { get; set; }
// navigation
[Required]
public FootprintComponentMapFile FootprintComponentMapFile { get; set; }
public FootprintComponentMap()
{
Footprint = String.Empty;
Value = String.Empty;
Component = 0;
Head = 0;
CompR = "0.00";
Polarized = "N";
Comment = String.Empty;
LibR = "0.00";
}
public FootprintComponentMap(FootprintComponentMap footprintComponentMap) : this()
{
Footprint = footprintComponentMap.Footprint;
Value = footprintComponentMap.Value;
Component = footprintComponentMap.Component;
Head = footprintComponentMap.Head;
CompR = footprintComponentMap.CompR;
Polarized = footprintComponentMap.Polarized;
Comment = footprintComponentMap.Comment;
LibR = footprintComponentMap.LibR;
}
public FootprintComponentMap(string footprint, string value, int componentNumber, int headNumber, string componentR,
string polarized, string libraryR, string comment) : this()
{
Footprint = footprint;
Value = value;
Component = componentNumber;
Head = headNumber;
CompR = componentR;
Polarized = polarized;
Comment = comment;
LibR = libraryR;
}
}
}
namespace TopazDomain.Classes.Extensions
{
public static class FootprintComponentMapFileExtensions
{
public sealed class FootprintComponentReadMapper : ClassMap<FootprintComponentMap>
{
public FootprintComponentReadMapper()
{
Map(m => m.Footprint).Index(0);
Map(m => m.Value).Index(1);
Map(m => m.Component).Index(2);
Map(m => m.Head).Index(3);
Map(m => m.CompR).Index(4);
Map(m => m.Polarized).Index(5);
Map(m => m.Comment).Index(6);
Map(m => m.LibR).ConvertUsing(row =>
{
if (row.TryGetField(7, out string field))
{
return field;
}
else
{
return String.Empty;
}
});
}
}
public sealed class FootprintComponentWriteMapper : ClassMap<FootprintComponentMap>
{
public FootprintComponentWriteMapper()
{
Map(m => m.Footprint).Index(0);
Map(m => m.Value).Index(1);
Map(m => m.Component).Index(2);
Map(m => m.Head).Index(3);
Map(m => m.CompR).Index(4);
Map(m => m.Polarized).Index(5);
Map(m => m.Comment).Index(6);
Map(m => m.LibR).Index(7);
}
}
public static bool ImportFootprintComponentMaps(this FootprintComponentMapFile footprintComponentMapFile,
string filename)
{
bool done = false;
using (var lineReader = new LineReader(filename))
using (var csv = new CsvReader(lineReader, CultureInfo.InvariantCulture))
{
csv.Configuration.RegisterClassMap<FootprintComponentReadMapper>();
footprintComponentMapFile.FootprintComponentMaps = csv.GetRecords<FootprintComponentMap>().ToList();
done = true;
}
return done;
}
public static bool ExportFootprintComponentMaps(this FootprintComponentMapFile footprintComponentMapFile,
string filename)
{
bool done = false;
CsvConfiguration cvsConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture);
cvsConfiguration.HasHeaderRecord = false;
using (var lineWriter = new StreamWriter(filename))
using (var csv = new CsvWriter(lineWriter, cvsConfiguration))
{
csv.Configuration.RegisterClassMap<FootprintComponentWriteMapper>();
csv.WriteRecords(footprintComponentMapFile.FootprintComponentMaps);
done = true;
}
return done;
}
}
}
您可以创建一个具有 8 个属性的新对象,并使用 ConvertUsing
有条件地映射第 8 列。
public class OldFoo
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class NewFoo
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class NewFooClassMap : ClassMap<NewFoo>
{
public NewFooClassMap()
{
Map(m => m.Id).Index(0);
Map(m => m.FirstName).Index(1);
Map(m => m.LastName).ConvertUsing(row => {
if(row.TryGetField(2, out string field))
{
return field;
}
else
{
return null;
}
});
}
}
public class Program
{
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, CultureInfo.InvariantCulture))
{
writer.WriteLine("1,Bob");
writer.WriteLine("2,Davey");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<NewFooClassMap>();
csv.Configuration.HasHeaderRecord = false;
var records = csv.GetRecords<NewFoo>().ToList();
}
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
writer.WriteLine("1,Bob,Barker");
writer.WriteLine("2,Davey,Jones");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<NewFooClassMap>();
csv.Configuration.HasHeaderRecord = false;
var records = csv.GetRecords<NewFoo>().ToList();
}
}
}
我有一堆 CSV 文件需要阅读,除了添加了一列外,它们都很相似。本质上,旧的 CSV 格式有 7 列,而新的将有 8 列。没有 headers。读取后,新列将是 defaulted/edited,然后文件在写出时将有 8 列 - 因此以后的读取现在将具有新列。
所以我正在尝试做类似这个 CvsHelper 示例的事情: Reading Multiple Record Types
唯一的区别在于文件中的列数 - 而不是标识字段值。
我在自己的 using() 中尝试了一个 CsvParser,并在文件的第一行中使用了一个 Read() 来确定列数,因为随后的 using() 中的 CsvReader 可以注册一个特定的计数ClassMap 为 CsvReader.GetRecords。但是,似乎没有 属性 或方法可以回答解析器遇到的列数。与 CsvReader.Read() 相同 - CsvReader.Context.ColumnCount 在 Read() 之后为零。任何想法/指示表示赞赏。
更新
这是我修改后的代码(长名称,我知道)- 感谢大卫的建议:
namespace TopazDomain.Classes
{
public class FootprintComponentMap : Entity<int>
{
private const int footprintWidth = 40;
[StringLength(footprintWidth)]
public string Footprint { get; set; }
private const int valueWidth = 40;
[StringLength(valueWidth)]
public string Value { get; set; }
public int Component { get; set; }
public int Head { get; set; }
private const int rotationWidth = 9;
[StringLength(rotationWidth)]
public string CompR { get; set; }
private const int polarizedWidth = 2;
[StringLength(polarizedWidth)]
public string Polarized { get; set; }
private const int commentWidth = 40;
public string Comment { get; set; }
[StringLength(rotationWidth)]
public string LibR { get; set; }
// navigation
[Required]
public FootprintComponentMapFile FootprintComponentMapFile { get; set; }
public FootprintComponentMap()
{
Footprint = String.Empty;
Value = String.Empty;
Component = 0;
Head = 0;
CompR = "0.00";
Polarized = "N";
Comment = String.Empty;
LibR = "0.00";
}
public FootprintComponentMap(FootprintComponentMap footprintComponentMap) : this()
{
Footprint = footprintComponentMap.Footprint;
Value = footprintComponentMap.Value;
Component = footprintComponentMap.Component;
Head = footprintComponentMap.Head;
CompR = footprintComponentMap.CompR;
Polarized = footprintComponentMap.Polarized;
Comment = footprintComponentMap.Comment;
LibR = footprintComponentMap.LibR;
}
public FootprintComponentMap(string footprint, string value, int componentNumber, int headNumber, string componentR,
string polarized, string libraryR, string comment) : this()
{
Footprint = footprint;
Value = value;
Component = componentNumber;
Head = headNumber;
CompR = componentR;
Polarized = polarized;
Comment = comment;
LibR = libraryR;
}
}
}
namespace TopazDomain.Classes.Extensions
{
public static class FootprintComponentMapFileExtensions
{
public sealed class FootprintComponentReadMapper : ClassMap<FootprintComponentMap>
{
public FootprintComponentReadMapper()
{
Map(m => m.Footprint).Index(0);
Map(m => m.Value).Index(1);
Map(m => m.Component).Index(2);
Map(m => m.Head).Index(3);
Map(m => m.CompR).Index(4);
Map(m => m.Polarized).Index(5);
Map(m => m.Comment).Index(6);
Map(m => m.LibR).ConvertUsing(row =>
{
if (row.TryGetField(7, out string field))
{
return field;
}
else
{
return String.Empty;
}
});
}
}
public sealed class FootprintComponentWriteMapper : ClassMap<FootprintComponentMap>
{
public FootprintComponentWriteMapper()
{
Map(m => m.Footprint).Index(0);
Map(m => m.Value).Index(1);
Map(m => m.Component).Index(2);
Map(m => m.Head).Index(3);
Map(m => m.CompR).Index(4);
Map(m => m.Polarized).Index(5);
Map(m => m.Comment).Index(6);
Map(m => m.LibR).Index(7);
}
}
public static bool ImportFootprintComponentMaps(this FootprintComponentMapFile footprintComponentMapFile,
string filename)
{
bool done = false;
using (var lineReader = new LineReader(filename))
using (var csv = new CsvReader(lineReader, CultureInfo.InvariantCulture))
{
csv.Configuration.RegisterClassMap<FootprintComponentReadMapper>();
footprintComponentMapFile.FootprintComponentMaps = csv.GetRecords<FootprintComponentMap>().ToList();
done = true;
}
return done;
}
public static bool ExportFootprintComponentMaps(this FootprintComponentMapFile footprintComponentMapFile,
string filename)
{
bool done = false;
CsvConfiguration cvsConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture);
cvsConfiguration.HasHeaderRecord = false;
using (var lineWriter = new StreamWriter(filename))
using (var csv = new CsvWriter(lineWriter, cvsConfiguration))
{
csv.Configuration.RegisterClassMap<FootprintComponentWriteMapper>();
csv.WriteRecords(footprintComponentMapFile.FootprintComponentMaps);
done = true;
}
return done;
}
}
}
您可以创建一个具有 8 个属性的新对象,并使用 ConvertUsing
有条件地映射第 8 列。
public class OldFoo
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class NewFoo
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class NewFooClassMap : ClassMap<NewFoo>
{
public NewFooClassMap()
{
Map(m => m.Id).Index(0);
Map(m => m.FirstName).Index(1);
Map(m => m.LastName).ConvertUsing(row => {
if(row.TryGetField(2, out string field))
{
return field;
}
else
{
return null;
}
});
}
}
public class Program
{
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, CultureInfo.InvariantCulture))
{
writer.WriteLine("1,Bob");
writer.WriteLine("2,Davey");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<NewFooClassMap>();
csv.Configuration.HasHeaderRecord = false;
var records = csv.GetRecords<NewFoo>().ToList();
}
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
writer.WriteLine("1,Bob,Barker");
writer.WriteLine("2,Davey,Jones");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<NewFooClassMap>();
csv.Configuration.HasHeaderRecord = false;
var records = csv.GetRecords<NewFoo>().ToList();
}
}
}