创建CSV文件时中途添加字段

thtygnil  于 2023-09-27  发布在  其他
关注(0)|答案(1)|浏览(71)

我需要从一个数据库表创建一个CSV文件,该表在其中一列中保存JSON数据。表中的每一行都可以包含一个具有不同变量的JSON。
我创建的CSV应该在所有行中包含所有变量的字段。

示例:

db表中的第1行:{"height":100,"weight":50}
db表中的第2行:{"color":"red"}
db表中的第3行:{"color":"blue","height":75}
要创建的CSV:

height,weight,color
100,50,
,,red
,75,blue

由于该表可能包含数十万行,我想知道是否有一种方法可以在从表中阅读行并创建CSV时中途添加字段,而无需读取整个表一次以获取所有字段,然后再次写入CSV。
我过去使用CSVHelper https://joshclose.github.io/CsvHelper/处理CSV操作,但我没有看到适合我的场景的选项。

wecizke3

wecizke31#

下面的代码从包含json数据的字符串列表中生成所需的输出。你可以从数据库中阅读数据:

public string GetCsv(string[] jsonValues) {

    var objectsAsDictionary = jsonValues.Select(_ =>
        JsonSerializer.Deserialize<Dictionary<string,object>>(_)).ToArray();

    using var textWriter =    new StringWriter();
    using var csv = new CsvWriter(textWriter, CultureInfo.InvariantCulture);
    var properties = objectsAsDictionary.SelectMany(_ => _.Keys)
        .Distinct().ToArray();

    foreach (var property in properties) {
        csv.WriteField(property);
    }
    csv.NextRecord();
    foreach (var item in objectsAsDictionary) {
        foreach (var property in properties) {
            object value = null;
            item.TryGetValue(property, out value);
            csv.WriteField(value);
        }
        csv.NextRecord();
    }
    return textWriter.ToString();
}

这是检查输出的测试:

var class1 = new Class1();
var rows = new[] {
    "{\"height\":100,\"weight\":50}",
    "{\"color\":\"red\"}",
    "{\"color\":\"blue\",\"height\":75}"
};

var result = class1.GetCsv(rows);
var expected = "height,weight,color" + Environment.NewLine +
"100,50," + Environment.NewLine +
",,red" + Environment.NewLine +
"75,,blue" + Environment.NewLine;
Assert.Equal(expected, result);

增量版本

如果第一行的前导分隔符的要求可以更改,则可以使用以下代码。
在这种情况下,每个值可以以增量方式处理,并且仅在末尾添加头部。
为了简单起见,我没有包括DB访问,但是可以用数据读取器替换可枚举参数。

public string GetCsv(IEnumerable<string> jsonValues) {
    var properties = new List<string>();        

    using var textWriter = new StringWriter();
    using var csv = new CsvWriter(textWriter, CultureInfo.InvariantCulture);      

    foreach (var jsonValue in jsonValues) {
        var item = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonValue);            
        foreach (var property in item.Keys) {
            if (!properties.Contains(property)) {
                properties.Add(property);
            }
        }
        foreach (var property in properties) {
            object value = null;
            item.TryGetValue(property, out value);
            csv.WriteField(value);
        }
        csv.NextRecord();
    }
    
    return string.Join(csv.Configuration.Delimiter, properties) + Environment.NewLine +
        textWriter.ToString();
}

在本例中,我不需要一次读取所有数据,但每次发现新属性时,我都会添加列。
结果如下(注意第二行不包括最后一个逗号):

height,weight,color
100,50
,,red
75,,blue

最后,进一步的处理可能会在第一行添加丢失的逗号。

相关问题