我确信它非常简单,但我正在努力弄清楚如何使用CSVHelper将数组写入文件。
我有一个班级,例如
public class Test
{
public Test()
{
data = new float[]{0,1,2,3,4};
}
public float[] data{get;set;}
}
我希望将数据与每个数组值一起写入单独的单元格中。我在下面有一个自定义转换器,而是为一个单元格提供其中的所有值。
我做错了什么?
public class DataArrayConverter<T> : ITypeConverter
{
public string ConvertToString(TypeConverterOptions options, object value)
{
var data = (T[])value;
var s = string.Join(",", data);
}
public object ConvertFromString(TypeConverterOptions options, string text)
{
throw new NotImplementedException();
}
public bool CanConvertFrom(Type type)
{
return type == typeof(string);
}
public bool CanConvertTo(Type type)
{
return type == typeof(string);
}
}
答案 0 :(得分:1)
不幸的是,它并没有像那样工作。由于您在转换器中返回,
,它将引用该字段,因为它是单个字段的一部分。
目前,实现目标的唯一方法是手动编写,这并不太可怕。
foreach( var test in list )
{
foreach( var item in test.Data )
{
csvWriter.WriteField( item );
}
csvWriter.NextRecord();
}
<强>更新强>
版本3支持读取和编写IEnumerable属性。
答案 1 :(得分:1)
要进一步详细了解 Josh Close 的答案,在此处您需要执行以下操作:编写最新版本(高于3.0的版本)的任何IEnumerable
(包括数组和通用列表) CsvHelper!
这里是被测课程:
public class Test
{
public int[] Data { get; set; }
public Test()
{
Data = new int[] { 0, 1, 2, 3, 4 };
}
}
以及显示如何保存的方法:
static void Main()
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
var list = new List<Test>
{
new Test()
};
csv.Configuration.HasHeaderRecord = false;
csv.WriteRecords(list);
writer.Flush();
}
}
此处的重要配置为csv.Configuration.HasHeaderRecord = false;
。只有使用此配置,您才能看到csv文件中的数据。
更多详细信息可以在CsvHelper的相关unit test cases中找到。
如果您正在寻找一种解决方案,用于存储类型为IEnumerable
的属性,其中元素的数量不同,以下示例可能会有所帮助:
using CsvHelper;
using CsvHelper.Configuration;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CsvHelperSpike
{
class Program
{
static void Main(string[] args)
{
using (var writer = new StreamWriter("db.csv"))
using (var csv = new CsvWriter(writer))
{
csv.Configuration.Delimiter = ";";
var list = new List<AnotherTest>
{
new AnotherTest("Before String") { Tags = new List<string> { "One", "Two", "Three" }, After="After String" },
new AnotherTest("This is still before") {After="after again", Tags=new List<string>{ "Six", "seven","eight", "nine"} }
};
csv.Configuration.RegisterClassMap<TestIndexMap>();
csv.WriteRecords(list);
writer.Flush();
}
using(var reader = new StreamReader("db.csv"))
using(var csv = new CsvReader(reader))
{
csv.Configuration.IncludePrivateMembers = true;
csv.Configuration.RegisterClassMap<TestIndexMap>();
var result = csv.GetRecords<AnotherTest>().ToList();
}
}
private class AnotherTest
{
public string Before { get; private set; }
public string After { get; set; }
public List<string> Tags { get; set; }
public AnotherTest() { }
public AnotherTest(string before)
{
this.Before = before;
}
}
private sealed class TestIndexMap : ClassMap<AnotherTest>
{
public TestIndexMap()
{
Map(m => m.Before).Index(0);
Map(m => m.After).Index(1);
Map(m => m.Tags).Index(2);
}
}
}
}
通过使用ClassMap
,可以再次启用HasHeaderRecord
(默认)。这里要特别注意,只有当元素数量不同的集合是最后一个属性时,此解决方案才有效。否则,集合需要具有固定数量的元素,并且ClassMap
需要进行相应的调整。
此示例还显示了如何使用private set
处理属性。为此,使用csv.Configuration.IncludePrivateMembers = true;
配置并在类上使用默认构造函数很重要。