使用 CSVhelper 将单个列更新为先前编写的 CSV 文件。我有 Java 代码,但无法将其翻译成 C#
Posted
技术标签:
【中文标题】使用 CSVhelper 将单个列更新为先前编写的 CSV 文件。我有 Java 代码,但无法将其翻译成 C#【英文标题】:Using CSVhelper to update a single column into a previously written CSV file . I have the code in Java but can't translate it into C# 【发布时间】:2021-12-07 21:24:07 【问题描述】:基本上我必须在测试完成执行之后读取和更新CSV文件(只有一列)(即,在测试执行开始时写入了一些值,并且那么我需要更新同一个文件以输入另一个值)。我还有一个 DateTime 错误,无论我尝试什么都无法解决。
CSV 开始测试示例
RunId ProductArea Product Component PageObject Control TimeTakenByLocatorJson
Run_645987 R201 BN2018.5 N778 BC1 C143
CSV 一栏测试后需要更新 (TimeTakenByLocatorJson)
RunId ProductArea Product Component PageObject Control TimeTakenByLocatorJson
Run_645987 R201 BN2018.5 N778 BC1 C143 2021-07-19
我一直在尝试使用 CSVhelper 更新 CSV 文件。我的代码是用 Java 编写的,当我尝试用 C# 翻译相同的代码时,它不起作用。
这是Java代码
public synchronized void writeEndCSV(String runId)
CSVWriter csvWriter = null;
try
String setupCSVLocation = Reporting.getSetupCSVLocation();
CSVReader csvReader = new CSVReader(new FileReader(setupCSVLocation));
List<String[]> records = csvReader.readAll();
for(int i=0;i<records.size();i++)
if(records.get(i)[SETUP_RUNID].equalsIgnoreCase(runId));
records.get(i)[SETUP_TimeTakenByLocatorJSON] = Reporting.getExecutionEndDate();
csvReader.close();
csvWriter = new CSVWriter(new FileWriter(setupCSVLocation));
csvWriter.writeAll(records);
csvWriter.flush();
csvWriter.close();
catch (Exception e)
e.printStackTrace();
这是我的 C# 代码(我是 .Net 新手,所以我不确定很多部分)
public void writeEnd(string runId)
var records = Enumerable.Empty<LocatorTime>();
try
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
// Don't write the header again.
HasHeaderRecord = false,
;
using (var reader = new StreamReader(@"D:\Reports\" + runId + @"\LocatorTime.csv"))
using (var csv = new CsvReader(reader, config))
//csv.Context.RegisterClassMap<LocatorTime>();
records = csv.GetRecords<LocatorTime>().ToList();
foreach (var record in records)
if (record.RunID == runId)
record.TimeTakenByLocatorJSON = DateTime.Now;
// Console.WriteLine("inside loop");
//Endof Stream Reader
using (var stream = File.Open(@"D:\Reports\" + runId + @"\LocatorTime.csv", FileMode.Append)) //not sure what the file mode should be
using (var writer = new StreamWriter(stream))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
csv.WriteRecords(records);
catch (Exception e)
Console.WriteLine(e);
//end func writeEnd
这是用于 csv 文件的类,也是 csv 文件中的列名
public class LocatorTime
public string RunID get; set;
public string ProductArea get; set;
public string Product get; set;
public string Component get; set;
public string PageObject get; set;
public string Control get; set;
public DateTime TimeTakenByLocatorJSON //only this value needs to be written for update at end of exec
get;
set;
/*error because of DateTime datatype how to resolve?*/ //LocatorTimeClass
/*public void SetExeDate() //tried this for removing DateTime error, didn't work
DateTime today = DateTime.Today; // As DateTime
string s_today = today.ToString("yyyy-MM-dd"); // As String
//TimeTakenByLocatorJSON = s_today.Trim();
TimeTakenByLocatorJSON = Convert.ToDateTime(s_today);
*/
public sealed class LocatorTimeMap : ClassMap<LocatorTime> //is mapping helpful for updating? currently commented out
public LocatorTimeMap()
Map(m => m.RunID).Index(0);
Map(m => m.ProductArea).Index(1);
Map(m => m.Product).Index(2);
Map(m => m.Component).Index(3);
Map(m => m.PageObject).Index(4);
Map(m => m.Control).Index(5);
Map(m => m.TimeTakenByLocatorJSON).Index(6); //error
我曾使用以下链接作为尝试更新 CSV 文件的参考,因此使用“HasHeaderRecord = false” https://joshclose.github.io/CsvHelper/examples/writing/appending-to-an-existing-file/
【问题讨论】:
能否也包含 CSV 样本? 我不能提供样本,因为我是这个网站的新手,但如前所述,csvfile 中的列名与提到的方法相同,基本上 csv 的内部就像这样 RunID| ProductArea|Product|.....|TimeTakenByLocatorJSON 您可以将部分 csv 粘贴到问题中并将其格式化为代码 您不想只使用数据库吗?您可以为任何希望使用 CSV 但将数据保存在一个系统中的系统按需生成 CSV,全部加载,循环遍历,查找记录,设置值,再次将其全部写入 csv,泡沫冲洗重复。 . 这就像拔指甲一样。你已经有了实体,你可以告诉 EF 让你成为一个漂亮的小 sqlite 数据库,这绝对是轻而易举的事,而且将所有代码减少到db.Things.First(t => t.RunId == x).SomeDate = DateTime.Now; db.SaveChanges()
会更有效。敢说它也可以解决日期格式问题
@CaiusJard 是的,但是分配给我的任务是使用 Csvhelper 将该 java 代码翻译成 C#,所以我必须这样做,没有任何问题
【参考方案1】:
我注意到了 3 件事。 1st - 在您的示例数据中,您有 7 个列标题,但只有 6 列数据。第二 - 您的“RunId”和“TimeTakenByLocatorJson”类名称与示例数据中的列不完全匹配。 3rd - 你的配置说“不要再写标题。”,但你正在用它来阅读。
对于第 1 期,我将假设这是印刷错误,我将添加另一列数据。
对于第 2 个问题,至少有 3 种处理方法。您已经通过映射到LocatorTimeMap
中的索引来处理它。我会给你第二种方法,将标题转换为小写。第三种方法是使用name attribute
对于第 3 期,标题 用于阅读,我假设您在编写时需要标题,因此您可以将 HasHeaderRecord = false
留在外面。
void Main()
writeEnd("Run_645987");
// You can define other methods, fields, classes and namespaces here
public void writeEnd(string runId)
var records = Enumerable.Empty<LocatorTime>();
try
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
// This will convert both the header coming in and your class property to lower case.
PrepareHeaderForMatch = args => args.Header.ToLower()
;
var input = new StringBuilder();
input.AppendLine("RunId,ProductArea,Product,Component,PageObject,Control,TimeTakenByLocatorJson");
input.AppendLine("Run_645987,R201,BN2018.5,N778,BC1,control1,2021-07-19");
using (var reader = new StringReader(input.ToString()))
//using (var reader = new StreamReader(@"D:\Reports\" + runId + @"\LocatorTime.csv"))
using (var csv = new CsvReader(reader, config))
records = csv.GetRecords<LocatorTime>().ToList();
foreach (var record in records)
if (record.RunID == runId)
record.TimeTakenByLocatorJSON = DateTime.Now;
//Endof Stream Reader
//using (var stream = File.Open(@"D:\Reports\" + runId + @"\LocatorTime.csv", FileMode.Append)) //not sure what the file mode should be
//using (var writer = new StreamWriter(stream))
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
csv.WriteRecords(records);
catch (Exception e)
Console.WriteLine(e);
//end func writeEnd
public class LocatorTime
public string RunID get; set;
public string ProductArea get; set;
public string Product get; set;
public string Component get; set;
public string PageObject get; set;
public string Control get; set;
public DateTime TimeTakenByLocatorJSON //only this value needs to be written for update at end of exec
get;
set;
//LocatorTimeClass
【讨论】:
谢谢,您的代码为我工作了一半。虽然它没有更新文件,但它确实删除了日期时间错误。还有关于PrepareHeaderForMatch = args => args.Header.ToLower()
,因为这是一个更大的项目的一小部分,是否可以在不改变任何标题的情况下阅读它?还有其他方法可以使用 CSVhelper 更新文件吗?
是否可以使用地图只更新一个特定的输入? input.AppendLine("Run_645987,R201,BN2018.5,N778,BC1,control1,2021-07-19");
而不是写所有的值可以说我只想将 control1 更新为 control3,因为我已经用索引映射了我的类,我可以说只更新那个特定的索引吗? else 我该怎么办?
您可以使用ClassMap<LocatorTime>
而不是PrepareHeaderForMatch
,并且可以使用您拥有的索引,也可以在ClassMap 中使用Name
。 Map(m => m.RunID).Name("RunId");
或者您可以使用 LocatorTime
类的 name 属性。上面有一个链接。我不确定是否要更新一个特定的输入。您可以使用这些值附加额外的一行,但如果您想实际更改它,我相信您将不得不读取并使用该单一更改再次写入整个文件。以上是关于使用 CSVhelper 将单个列更新为先前编写的 CSV 文件。我有 Java 代码,但无法将其翻译成 C#的主要内容,如果未能解决你的问题,请参考以下文章
使用 CsvHelper 将 CSV 文件中的编号列映射到数组
如何在 C# 中使用 csvHelper 将两个单独列中的日期和时间合并到一个新的日期时间列中