c#中的JSON到CSV和CSV到JSON

本文关键字:CSV JSON 中的 | 更新日期: 2023-09-27 18:17:12

我一直在寻找一种方法将json文件转换为csv,反之亦然使用c#。我在谷歌上搜索了一下,什么也没找到。到目前为止,我所尝试的一切都不是关于堆栈溢出的答案,只是对我不起作用。有人知道任何工具或教程,我可以看看如何完成这个与。net框架?通常我会张贴我尝试过的东西,但我显然离这里很远,所以毫无意义。

c#中的JSON到CSV和CSV到JSON

妥协与问题

你可以在。net框架中完成这一点,但是由于层次结构和集合,没有一个清晰明显的方法来直接完成这一点。我的意思是,CSV数据非常扁平且非结构化,而JSON数据非常有组织且迭代。让我们来看一个简单的JSON数据块,它看起来像这样:

{
    "Data": [
        {
            "Name":"Mickey Mouse",
            "Friends":[ "Pluto", "Minnie", "Donald" ]
        },
        {
            "Name":"Pluto",
            "Friends":[ "Mickey" ]
        }
    ]
}

最明显的CSV文件可能是:

Name,Friend
Mickey Mouse,Pluto
Mickey Mouse,Minnie
Mickey Mouse,Donald
Pluto,Mickey

这是更简单的转换但假设你只有那个CSV文件。JSON应该是什么样子并不是很明显。有人可能会说JSON应该是这样的:

{
    "Data": [
        { "Name":"Mickey Mouse", "Friend":"Pluto" },
        { "Name":"Mickey Mouse", "Friend":"Minnie" },
        { "Name":"Mickey Mouse", "Friend":"Donald" },
        { "Name":"Pluto", "Friend":"Mickey" },
    ]
}

生成的JSON文件与输入的JSON文件非常不同。我的观点是,这不是一个简单/明显的转换,所以任何现成的或复制/粘贴的解决方案都是不完美的。无论你的解决方案是什么,你都必须做出妥协或明智的决定。


。. NET框架选项

现在我们已经解决了这个问题,. net为您提供了一些开箱即用的功能,并且还提供了一些很好的nuget选项。如果你想利用纯粹的。net功能,你可以使用以下两个SO的组合:

  1. 不完美,但这个答案有一些很棒的代码,可以让你开始在逻辑中生成CSV文件
  2. 这个问题和由此产生的答案提供了一些关于仅使用。net框架而不使用任何第三方实用程序生成JSON的好信息。

你应该能够应用这两个链接中的概念,加上我在这篇文章的第一个"妥协和问题"部分中需要做出的妥协和明智的决定来完成你需要的。


我以前做过的事

我已经做了类似的事情,我实际上使用了Microsoft.VisualBasic.FileIO命名空间中的一些功能(在c#应用程序中工作得很好),除了Web API的序列化功能外,还使用动态对象(使用动态关键字)作为中介来完成CSV->JSON转换。代码如下所示。它不是非常强大,并且做出了一些重大的妥协,但它对我来说工作得很好。如果您想尝试这样做,您必须创建自己的反向版本,但正如我在第一节中提到的,这确实是最简单的部分。

using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Web.Http;
// NOTE: This is not purely my code. This was put together
// with the help of other SO questions that I wish I had the
// links to so I could credit them. You probably will find
// some chunk(s) of this code elsewhere on SO.
namespace Application1.Controllers
{
    public class Foo
    {
        public string Csv { get; set; }
    }
    public class JsonController : ApiController
    {
        [HttpPost]
        [Route("~/Csv/ToJson")]
        public dynamic[] ConvertCsv([FromBody] Foo input)
        {
            var data = CsvToDynamicData(input.Csv);
            return data.ToArray();
        }
        internal static List<dynamic> CsvToDynamicData(string csv)
        {
            var headers = new List<string>();
            var dataRows = new List<dynamic>();
            using (TextReader reader = new StringReader(csv))
            {
                using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader))
                {
                    parser.Delimiters = new[] {","};
                    parser.HasFieldsEnclosedInQuotes = true;
                    parser.TrimWhiteSpace = true;
                    var rowIdx = 0;
                    while (!parser.EndOfData)
                    {
                        var colIdx = 0;
                        dynamic rowData = new ExpandoObject();
                        var rowDataAsDictionary = (IDictionary<string, object>) rowData;
                        foreach (var field in parser.ReadFields().AsEnumerable())
                        {
                            if (rowIdx == 0)
                            {
                                // header
                                headers.Add(field.Replace("''", "_").Replace("/", "_").Replace(",", "_"));
                            }
                            else
                            {
                                if (field == "null" || field == "NULL")
                                {
                                    rowDataAsDictionary.Add(headers[colIdx], null);
                                }
                                else
                                {
                                    rowDataAsDictionary.Add(headers[colIdx], field);
                                }
                            }
                            colIdx++;
                        }
                        if (rowDataAsDictionary.Keys.Any())
                        {
                            dataRows.Add(rowData);
                        }
                        rowIdx++;
                    }
                }
            }
            return dataRows;
        }
    }
}

如果你想要更健壮的东西,那么你总是可以利用这些伟大的项目:

  1. JSON。它可以很好地从动态对象创建JSON。考虑到您不使用Web API,这将是第一个地方,我将寻找采取dynamic[]返回值并将其转换为JSON。
  2. CsvHelper

除了使用多个库的组合来完成JSON和CSV之间的转换之外,Cinchoo ETL还提供了统一的接口来完成这两种格式之间的转换。

示例JSON文件:

[
   {
      "Name" : "Xytrex Co.",
      "Description" : "Industrial Cleaning Supply Company",
      "AccountNumber" : "ABC15797531"
   },
   {
      "Name" : "Watson and Powell, Inc.",
      "Description" : "Law firm. New York Headquarters",
      "AccountNumber" : "ABC24689753"     
   }
]

生成CSV文件:

Name,Description,AccountNumber
Xytrex Co.,Industrial Cleaning Supply Company,ABC15797531
Watson and Powell Inc.,Law firm. New York Headquarters,ABC24689753

JSON到CSV:

using (var p = ChoJSONReader.LoadText(json))
{
    using (var w = new ChoCSVWriter(Console.Out)
        .WithFirstLineHeader()
        )
    {
        w.Write(p);
    }
}

样本小提琴: https://dotnetfiddle.net/T3u4W2

CSV to JSON:

using (var p = ChoCSVReader.LoadText(csv)
        .WithFirstLineHeader()
    )
{
    using (var w = new ChoJSONWriter(Console.Out))
    {
        w.Write(p);
    }
}

样本小提琴: https://dotnetfiddle.net/gVlJVX

就像jasxidian提到的,问题是json可以有层次结构,而csv没有。

所以,我可以给你两个建议:

  • 创建一个分层csv,不应该是太多的努力:

    "Id";"Name";"Age";"Type"
        "FriendId"
    1;"Mickey Mouse";20;"mouse"
        2
        3
        4
    2;"Pluto";7;"dog"
        1
    3;"Minnie";20;"mouse"
    4;"Donald";22;"duck"
    
  • 创建多个文件,可能会更费力,但更美观,更动态,当你使用。从数据库导出/导入。也许这个链接可以帮助你:http://www.snellman.net/blog/archive/2016-01-12-json-to-multicsv

    • all.csv(存储所有字符)

      "Id";"Name";"Age";"Type"
      1;"Mickey Mouse";20;"mouse"
      2;"Pluto";7;"dog"
      3;"Minnie";20;"mouse"
      4;"Donald";22;"duck"
      
    • friends.csv(存储所有关系)

      "FriendKey1";"FriendKey2"
      1;2
      2;1
      1;3
      1;4