【问题标题】:C# CSV to JSON per row每行 C# CSV 到 JSON
【发布时间】:2017-05-02 22:56:01
【问题描述】:

主要编辑:我在解释方面做得不好:(

我有两个班级:

public class UserDefinitions// a list of 'Items', each'group of items belong to a user. I handle User logic elsewhere, and it works flawlessly.  
    {
        public List<Item> items { get; set; }
    }
public class Item //the User definitions. A user could have 1 or 15 of these. They would all be a single 'line' from the CSV file.
    {

       public string definitionKey { get; set; }
       public string defName { get; set; }
       public string defValue { get; set; }

    }

我想用 CSV 文件构建。我构建了这个 CSV 文件,所以我每次都使用相同的参数。

我在公司的数据库上运行 SQL 以生成如下结果:http://i.imgur.com/gS1UJot.png

然后我像这样读取文件:

class Program
{
    static void Main(string[] args)
    {
        var userData = new UserDefinitions();
        var csvList = new List<Item>();
        string json = "";
        string fPath = @"C:\test\csvTest.csv";
        var lines = File.ReadAllLines(fPath);
        Console.WriteLine(lines);
        List<string> udata = new List<string>(lines);
        foreach (var line in udata)
        {
            string[] userDataComplete = line.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);// this cleans any empty cells from the CSV  

            csvList.Add(new Item { definitionKey = userDataComplete[1], defName = userDataComplete[2], defValue = userDataComplete[3] });
        }

        json = JsonConvert.SerializeObject(csvList); //everything below is for debugging/tracking progress  
        Console.WriteLine(json);
        Console.ReadKey();

        StreamWriter sw = new StreamWriter("C:\\test\\testjson.txt");
        sw.WriteLine(json);
        sw.Close();

     }

  }

这几乎可以满足我的要求。输出 json 来自 csv 数据的第一个“列”

[{"definitionKey":"uuid1","defName":"HairColor","defValue":"Brown"},{"definitionKey":"uuid1","defName":"HairColor","defValue" :"Blonde"},{"definitionKey":"uuid1","defName":"HairColor","defValue":"Blue"}]

以屏幕截图为例,wanted输出应该是

[{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Brown"},{"definitionKey":"uuid2","defName":"FreckleAmount","defValue" :"50"}] [{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Blonde"},{"definitionKey":"uuid2","defName":"FreckleAmount","defValue":"null "}] [{"attributeDefinitionKey":"uuid1","name":"HairColor","value":"Blue"},{"definitionKey":"uuid3","defName":"Tattoos","defValue":"5 "}]

我不能随意挑选某些方面,或将它们应用于项目。例如,可能有 10 个用户或 5000 个用户,但定义密钥将始终为 [1],添加 '3' 将获得每个后续定义密钥。就像 defName 将始终在 [2] 位置,添加 3 将获得每个后续的 defName(如果有的话),这都是每行。

我知道我必须添加一些 +3 逻辑,但不太确定如何合并它。也许是一个for循环? foreach 循环之后的嵌套 for 循环?我觉得我错过了一些明显的东西!

再次感谢您的帮助

【问题讨论】:

  • 用户在 CSV 文件中是否有多行?你想要所有的“项目”按他们所属的用户排序吗? csv 文件中的每个条目是否有不同数量的列?
  • 一个用户,只占用一行。单行中的所有“项目”都属于一个用户,并且在一个 CSV 文档中可能总共有 15 个事物(每个事物都有一个 id、名称、值)用户 1 可以在所有这些事物下都有一个值,用户 2 可以有10 个事物的值,用户 3 可能只有 5 个具有值的事物..但所有事物都可用。如果它们没有事物 1 的值,则单元格将为空白。我是清楚还是超级混乱?
  • 非常令人困惑,您必须展示或举例说明 CSV 的实际外观。因为您说用户只有一行,而一个项目只有一行。那么他们混在一起了吗?还是您的意思是 CSV 是代表项目的所有行,其中包含具有用户 ID 的列
  • 对不起,令人困惑!这是一个示例的屏幕截图,认为它是最简单的...i.imgur.com/gS1UJot.png

标签: c# arrays json csv split


【解决方案1】:

这会逐行读取 csv 行并将每一行转换为 json,同时适应列数的变化。

这仅在 CSV 遵循您的规则时才有效:
一个用户 ID 和
x 数量的“事物”,每个“事物”有 3 列。

private static void Main(string[] args)
    {
        var file = new StreamReader(@"C:\test\csvTest.csv");
        string line;
        var itemsJson = new List<string>();
        file.ReadLine();
        while ((line = file.ReadLine()) != null)
        {
            var sb = new StringBuilder();
            var fields = line.Split(',');


            sb.Append(GetKeyValueJson("UserId", fields[0]));
            for (var i = 1; i < fields.Length; i += 3)
            {
                var x = (i + 3) / 3;
                sb.Append(GetKeyValueJson($"Thing {i + x} ID", fields[i]));
                sb.Append(GetKeyValueJson($"Thing {i + x} ID", fields[i + 1]));


                sb.Append(i + 3 == fields.Length
                    ? GetKeyValueJson($"Thing {i + x} ID", fields[i + 2], true)
                    : GetKeyValueJson($"Thing {i + x} ID", fields[i + 2]));
            }

            itemsJson.Add(WrapJson(sb.ToString()));
        }

        var json = WrapItems(itemsJson);


        Console.ReadLine();
    }

    private static string GetKeyValueJson(string id, string value, bool lastPair = false)
    {
        var sb = new StringBuilder();
        sb.Append('"');
        sb.Append(id);
        sb.Append('"');
        sb.Append(':');
        sb.Append('"');
        sb.Append(value);
        sb.Append('"');
        if (!lastPair)
            sb.Append(',');

        return sb.ToString();
    }

    private static string WrapJson(string s)
    {
        var sb = new StringBuilder();
        sb.Append('{');
        sb.Append(s);
        sb.Append('}');

        return sb.ToString();
    }

    private static string WrapItems(List<string> jsonList)
    {
        var sb = new StringBuilder();
        sb.Append('"');
        sb.Append("Items");
        sb.Append('"');
        sb.Append(':');
        sb.Append('[');
        sb.Append(jsonList.Aggregate((current, next) => current + "," + next));
        sb.Append(']');

        return WrapJson(sb.ToString());
    }
}

它不是很漂亮,排序会很困难,但它应该适应列的数量,只要它是 3 的。

【讨论】:

  • 谢谢!我需要字段或“事物”具有适应性。有时有 3 个东西,有时有 15 个“东西”,每个都有一个 id、name 和 value。我在想也许读取每个 row 的 csv,然后用 for 循环为每一行分配 setter
  • 也许有些异步。船长必须潜得更深!
  • @B_happy_chap 我已经编辑了解决方案,只要每个“事物”有 3 列,它就应该接受任意数量的“事物”。不幸的是,你不会得到类的对象,只有 json 格式的字符串。
  • 嗯关闭。我认为我在解释我的问题时很糟糕。可能与我找不到我要找的东西的原因相同!我有一个 json 转换器,使用 json.net。使用你的一些代码,我修改了我的。我将重新编辑主要帖子以反映更改。
  • 我只说关闭,因为 sr 占用了太多内存,我可能会处理一个 10 行的文档,或者 15000 行的文档,最多 45-50 列。 'ReadAllLines' 将内容放入内存并允许更快的处理,尤其是在我掌握了解决方案之后,我正在将其用于企业代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
  • 2017-08-17
  • 1970-01-01
相关资源
最近更新 更多