因此,在绝望地拉了一个小时之后,我决定听从这里的每个人的建议,而 不要实施我自己的CSV解析器 。
所以我改为使用FileHelpers。
但是我在正确使用它时遇到了一些麻烦。
我的CSV文件看起来像这样:
50382018,50319368,eBusiness Manager,IT02,3350_FIB4,IT,2480
50370383,50373053,CRM Manager,IT01,3200_FIB3,xyz,2480
50320067,50341107,"VP, Business Information Officer",IT03,3200_FI89,xyz,2480
50299061,50350088,Project Expert,IT02,8118_FI09,abc,2480
我对FileHelpers(特别是CsvEngine
)的需求在第3行-请注意用引号引起来的第三列,因为它有一个内部逗号(否则用作分隔符)。
我读取文件的代码是这样的:
var co = new FileHelpers.Options.CsvOptions("Employee", columnDeliminator, 7);
var ce = new CsvEngine(co);
var records = ce.ReadFile(pathToCSVFile);
工作正常-有点。它可以正确地解析行并使用封闭的定界符识别值。
但是。
ReadFile()
方法的返回值为object[]
。而且它的内容似乎是一种动态类型。
看起来像这样-列名为“ Field_1”,“ Field_2”等。
我创建了一个“数据类”,用于保存已解析的行,它看起来像这样:
public class Employee
{
public string DepartmentPosition;
public string ParentDepartmentPosition;
public string JobTitle;
public string Role;
public string Location;
public string NameLocation;
public string EmployeeStatus;
}
是否可以使用FileHelpers的CsvEngine
类来返回强类型数据?
如果我只能使用FileHelpers的“基本”解析器,则可以使用以下代码:
var engine = new FileHelperEngine<Employee>();
var records = engine.ReadFile("Input.txt");
是否可以让CsvEngine
返回“ Employee”类的实例?还是我必须编写自己的映射代码来支持此操作?
答案 0 :(得分:0)
documentation通过一种简单的方式为我工作:
首先在课堂上,它需要几个装饰器:
编辑:使用FieldQuoted装饰器来解析引号中的所有内容,并忽略包含的逗号
[DelimitedRecord(",")]
class Person
{
[FieldQuoted]
public string Name { get; set; }
[FieldConverter(ConverterKind.Int32)]
public int Age { get; set; }
public string State { get; set; }
}
DelimitedRecord
用于类和预期的分隔符(如果以后发生更改,可能会出现问题。
和它的FieldConverter出现,除了字符串以外。
然后稍微改变您的阅读方式:
var fhr = new FileHelperEngine<Person>();
var readLines = fhr.ReadFile(pathToFile);
然后它可以工作,强类型输入:
foreach(var person in readLines)
{
Console.WriteLine(person.Name);
}
答案 1 :(得分:0)
使用CsvHelper作为可行的替代方法,并假定CSV文件没有标题,
可以为Employee
类创建映射,例如
public sealed class EmployeeClassMap : ClassMap<Employee> {
public EmployeeClassMap() {
Map(_ => _.Location).Index(0);
Map(_ => _.NameLocation).Index(1);
Map(_ => _.JobTitle).Index(2);
//...removed for brevity
}
}
将索引映射到强类型对象模型上的相应属性的地方。
要使用此映射,您需要在配置中注册该映射。
using (var textReader = new StreamReader(pathToCSVFile)) {
var csv = new CsvReader(textReader);
csv.Configuration.RegisterClassMap<EmployeeClassMap>();
var records = csv.GetRecords<Employee>();
//...
}
答案 2 :(得分:0)
@ shamp00的答案正确-我也在FileHelper escape delimiter上找到了它。
我上了模型课,并按照建议装饰了每个属性:
(我可能不需要装饰所有属性,但现在可以使用)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
let nextVC = segue.destination as! UINavigationController
let dest = nextVC.topViewController as! ViewController
let ind = sender as! customTableViewCell
let nTxt = nameTxt.text?.description
let pTxt = phoneTxt.text?.description
let eTxt = emailTxt.text?.description
let dTxt = dobTxt.text?.description
ind.lb1 = "\(nTxt!)"
ind.lb2 = "\(pTxt!)"
ind.lb3 = "\(eTxt!)"
ind.lb4 = "\(dTxt!)"
}
}
现在我只需要以下代码:
[DelimitedRecord((","))]
public class Employee
{
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string DepartmentPosition;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string ParentDepartmentPosition;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string JobTitle;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string Role;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string Location;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string NameLocation;
[FieldQuoted('"', QuoteMode.OptionalForBoth)]
public string EmployeeStatus;
}
答案 3 :(得分:-1)
如果该库不起作用,您还可以尝试使用内置的.Net CSV解析器TextFieldParser。例如:https://coding.abel.nu/2012/06/built-in-net-csv-parser/
已添加: 对于类型(具有自动转换):
static void run()
{
// split with any lib line of CSV
string[] line = new string[]{"john", "doe", "201"};
// needed prop names of class
string[] propNames = "fname|lname|room".Split('|');
Person p = new Person();
parseLine<Person>(p, line, propNames);
}
static void parseLine<T>(T t, string[] line, string[] propNames)
{
for(int i = 0;i<propNames.Length;i++)
{
string sprop = propNames[i];
PropertyInfo prop = t.GetType().GetProperty(sprop);
object val = Convert.ChangeType(line[i], prop.PropertyType);
prop.SetValue(t, val );
}
}
class Person
{
public string fname{get;set;}
public string lname{get;set;}
public int room {get;set;}
}