c# - 当标题数量不固定时使用 CsvHelper 创建 csv 文件
问题描述
我有 json 对象的列表。每个 json 对象都具有公共属性和该 json 对象独有的一些属性。像下面的示例
{"FirstName":"foo","LastName":"bar"}
{"FirstName":"jhon","LastName":"dow"}
{"FirstName":"james","LastName":"smith","Age":26}
{"LastName":"jones","Age":30, "Address":"1234 Test Drive"}
我想使用CsvHelper创建 CSV 报告,其中每个属性都是标题。当属性不存在时,该列的值应为空
这是我当前的实现,当然没有考虑额外的属性
var records = new List<dynamic>();
foreach (var jObj in result)
{
var record = new ExpandoObject();
foreach (var property in jObj)
{
record.TryAdd(property.Key, property.Value.ToString());
}
records.Add(record);
}
using (var writer = new StreamWriter(filePath))
{
using (var csv = new CsvWriter(writer))
{
csv.WriteRecords(records);
}
}
所以在上面的例子中,结果 csv 应该有 4 个 headers
FirstName
, LastName
,Age
和Address
请注意,记录的数量可能是数千
下面的更新 1
是我的临时解决方案,直到我找到更好的方法来做到这一点而无需循环两次
[Fact]
public async Task CreateCSVFromJObjects()
{
// arrange
var list = new JObject[]
{
JObject.FromObject(new { FirstName = "foo",LastName = "bar" }),
JObject.FromObject(new { FirstName = "john",LastName = "doe" }),
JObject.FromObject(new { FirstName = "james",LastName = "smith", Age = 26 }),
JObject.FromObject(new { LastName = "bar", Address = "123 Test Drive" })
}.ToList();
//act
var headers = new HashSet<string>();
foreach (var j in list)
{
foreach (var p in j)
{
if (!headers.Contains(p.Key))
{
headers.Add(p.Key);
}
}
}
using (var writer = new StreamWriter("C:\\temp\\test.csv"))
{
using (var csv = new CsvWriter(writer))
{
foreach (var header in headers)
{
csv.WriteField(header);
}
await csv.NextRecordAsync();
foreach (var jObj in list)
{
foreach (var header in headers)
{
var token = jObj[header];
if (token != null)
{
csv.WriteField(token.ToString());
}
else
{
csv.WriteField("");
}
}
await csv.NextRecordAsync();
}
}
}
}
解决方案
如果结果不必与处理一起实时流式传输,则在与流写入相同的循环内创建和维护标头集和标头列表可能更有效,跳过标头写入首先是流。然后您可以构建一个新流,写入标题,然后将原始流复制到其中。
是否可以使用内存流进行中间写入取决于您的内存需求。
每个请求的伪代码。这实际上只是对现有代码的一个小重新排列。它需要更少的循环,但需要更多的内存或磁盘。问题的性质需要权衡。
Stream intermediate_stream // memory or file
List headers // only add a set if List is a bottleneck (1000s of properties); list required to maintain ordering
foreach ( obj in list ) :
foreach ( prop_name in obj.props )
headers.add_if_unique(prop_name)
foreach ( name in headers ) // to preserve ordering in output
intermediate_stream.write(obj.prop_value(name))
Stream final_stream
final_stream.write(headers)
intermediate_stream.copy_to(final_stream)
推荐阅读
- javascript - 与数组进行比较并根据值更新的代码永远不会返回更新
- python - Composer 没有看到数据流作业成功
- firebase - 如何使用 Firebase 身份验证将帐户与不同的提供商关联?
- javascript - 如何在 japi joi 中进行嵌套对象验证
- metrics - keras.metrics.AUC() 用于三元分类问题
- mdx - MDX 多个条件过滤多个维度
- javascript - 离线移动生成 6 位代码用于 2 因素身份验证
- angular - 将 Angular 8 应用程序部署到 IIS
- xml - 一种在spring xml中将一个bean指向另一个bean的方法
- javascript - 通过javascript将特定项目移动到div元素的底部