1.什么是csv文件?
CSV是一种通用的、相对简单的文件格式,具有以下特征:
- 1纯文本 ,使用某个字符集,比如ASCII、Unicode、EBCDIC或GB2312;
- 2由记录组成(典型的是每行一条记录);
- 3.每条记录被分隔符分隔为字段(典型分隔符有逗号、分号或制表符;有时分隔符可以包括可选的空格);
- 4.每条记录都有同样的字段序列。
下面是一个实际 CSV 文件,让大家有一个感性的认识。我们选的是 Sjojo_Rescan 的 CSV 文件 (Sjojo 是 ASW- 亚洲扫图风的成员之一)。
FileName,ByeCount,CRC,
sj_mino1001.jpg,715282,4FB55FE8,
sj_mino1002.jpg,471289,93203C5C,
sj_mino1003.jpg,451929,C4E80467,
这个csv文件中,有3行记录,每个记录有3个字段,字段名分别分:FileName,ByeCount,CRC所有字段都是字符型!
好了,大概了解了csv之后,我们就看看如何解析读取csv文件记录和字段内容。
C# CSVhelper库,有CSVReader和CSVWriter类,分别用来读取和写入CSV内容,今天我们先讨论用CSVReader类来读取CSV文件内容。
一.将CSV文件所有行和字段逐行性全部读进来,
1.将csv文件以recource文件的形式加入到VS项目代码中,如下:
cs
/// <summary>
/// Looks up a localized string similar to ModelName,ThermalModel,PDCSV,IMSAssemblyNumber,ModelType,
///AC F2-A 24-280-001,F2A_24V_IPB014N06N_NE222_KDP153.mat,AC F2-A 24-280-001.csv,470672420,1,
///AC F2-A 24-280-001,OnSemi,AC F2-A 24-280-001 PDC-2038.csv,470672421,1,F2-A_24V_FDB0170N607L_NE236
///AC F2-A 48-240-001,F2A_48V_FDB1D7N10CL7_NE249_KDP89.mat,AC F2-A 48-240-001 PDC-10001.csv,470674820,1,
///AC F2-A 48-240-001,F2A_48V_IPB017N10N5_NE248_KDP82.mat,AC F2-A 48-240-001 PDC-2011.csv,470674821,1,
///AC F2-A 48-240-051,F2A_48V_FDB1D7N10CL7_NE249_KDP89.mat,AC [rest of string was truncated]";.
/// </summary>
internal static string model_release {
get {
return ResourceManager.GetString("model_release", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to VariableName,AddressCAN,DataType,MemoryArea,FactoryDefault,FeatureArea,Release
///Cal_KSI,0x4F2500,UINT16,NV_PRODUCT,2001,Calibrations,2.1.0.8
///CAN_ConfigLock,0x319601,UINT8,NV_BOOT,0,CAN,2.3.0.0
///CAN_2_ConfigLock,0x319602,UINT8,NV_BOOT,0,CAN,2.3.0.0
///canopen_mandatory_hardware_version,0x100900,STRING,NV_STRINGS,FSERIES_PRIMARY.1.0,IO.Config,2.1.0.8
///CAN_Open_Product_Code,0x101802,INT32,NV_PRODUCT,0x0005F4D2,CAN,2.1.0.8
///CAN_Node_Id,0x200001,UINT16,NV_BOOT,0x0026,CAN,2.1.0.8
///CAN_2_Node_Id,0x200002,UINT16,NV_ [rest of string was truncated]";.
/// </summary>
internal static string _params {
get {
return ResourceManager.GetString("_params", resourceCulture);
}
}
2.Main方法中代码读取
cs
static void Main(string[] args)
{
using (TextReader tr = new StringReader(Resource.model_map_release))
{
using (CsvReader csv = new CsvReader(tr))
{
//读取第一行表头
//ModelName,ThermalModel,PDCSV,IMSAssemblyNumber,ModelType,
//GetField 方法依赖于 CSV 文件的标题行(第一行),它需要先调用 csv.Read() 和 csv.ReadHeader() 方法来读取并解析标题行。
//如果跳过了标题行或没有调用 ReadHeader(),则无法通过列名获取字段。
csv.Read();
csv.ReadHeader();
string modelName = csv.GetField("ModelName");
string ThermalModel = csv.GetField(1);
string PDCSV = csv.GetField(2);
string IMSAssemblyNumber = csv.GetField(3);
string ModelType = csv.GetField(4);
//按行循环读取csv数据区域内容,直到read方法返回false即读取结束
int rowcount = 0;
while (csv.Read())
{
//获取当前行的field0内容
string field0 = csv.GetField("ModelName");
//获取当前行的field2内容
string field1 = csv.GetField("ThermalModel");
//获取当前行的field2内容
string field2 = csv.GetField("PDCSV");
//获取当前行的field Index = 3 的字段内容,并转换成整数
var field3 = csv.GetField<int>(3);
//获取当前行的field name = "IMSAssemblyNumber"的字段内容,并转换成整数
var field3_IMSAssemblyNumber = csv.GetField<int>("IMSAssemblyNumber");
//获取当前行的field4内容
string field4 = csv.GetField(4);
rowcount++;
}
}
}
以上是将csv文件中的内容全部读出来,想要处理或筛选部分内容就不是很方便,接下来我们用一些高级的方法定义读取csv的字段映射,以及用LINQ筛选出我们想要的数据.demo如下
首先建立一个类ThermalModel,定义需要的属性,用来对应csv文件中的字段,建立csvmodel字段和query类型属性的映射关系;csv中不需要获取的字段可以在类中不添加对应的属性,比如ThermalModel列,代码如下:
cs
public class ThermalModelMap : ClassMap<ThermalModel>
{
public ThermalModelMap()
{
Map(m => m.ModelName);
Map(m => m.PDCSV);
Map(m => m.IMSAssemblyNumber);
Map(m => m.ModelType);
}
}
public class ThermalModel
{
/// <summary>
/// Gets or sets the model name of the thermal model
/// </summary>
public string ModelName { get; set; }
/// <summary>
/// Gets or sets the product model (thermal model PD file)
/// </summary>
public string PDCSV { get; set; }
/// <summary>
/// Gets or sets the IMS board part number
/// </summary>
public string IMSAssemblyNumber { get; set; }
public string ModelType { get; set; }
}
cs
static void Main(string[] args)
{
//获取csv文件中的内容
string modelsContext = Resource.ResourceManager.GetObject("model_map_release").ToString();
//将csv内容转成TextReader对象
using (TextReader reader = new StringReader(modelsContext))
{
using (CsvReader csv = new CsvReader(reader))
{
//建立类型的属性与csv文件字段映射注册关系,取4个字段,去掉CSV中不需要的ThermalModel列
csv.Configuration.RegisterClassMap<ThermalModelMap>();
//将csv中的数据一次性全部读出来,转成泛型集合对象
var modellist = csv.GetRecords<ThermalModel>().ToList();
//筛选需要的内容
var modeldNeed = modellist.Where(m => int.Parse(m.ModelType) == 1);
}
}
}
ClassMap<T>类与CSV文件字段可以建立复杂的映射关系,类中定义的属性与CSV字段都有一一对应的关系,如果类中某个属性不用了,可以在建立映射关系时,用Ignore方法不建议该映射关系。如下:
cs
public sealed class ProductMap : ClassMap<Product>
{
public ProductMap()
{
//类的ID属性,映射到CSV的ProductID列
Map(m => m.Id).Name("ProductID");
//类的Name属性,映射到CSV的ProductName列
Map(m => m.Name).Name("ProductName");
// 将CSV "Price" 列的值转换为 decimal,并移除货币符号
Map(m => m.Price).ConvertUsing(row => decimal.Parse(row.GetField<string>("Price").Replace("$", "")));
// 忽略 "CreatedAt" 属性
Map(m => m.CreatedAt).Ignore();
}
}
public class Product
{
public string ProductName { get; set; }
public int ProductID { get; set; }
public string CreatedAt { get; set; }
}
注册时机 :RegisterClassMap 必须在调用 GetRecords<T>() 或 WriteRecords() 之前完成。
配置作用域 :RegisterClassMap 作用于当前的 CsvReader 或 CsvWriter 实例的配置。