C#中的JSON字符串转CSV和CSV转JSON转换

28

我正在我的asp.net web API项目中使用JSON/CSV文件,并尝试使用CSVHelperServiceStack.Text库,但无法使其工作。

包含数组的JSON文件是动态的,可能有任意数量的字段。

我使用streamreader读取文件,然后需要将其转换为CSV文件,以便最终用户可以下载它。

示例文件文本

[{"COLUMN1":"a","COLUMN2":"b","COLUMN3":"c","COLUMN4":"d","COLUMN5":"e"},
 {"COLUMN1":"a","COLUMN2":"b","COLUMN3":"c","COLUMN4":"d","COLUMN5":"e"}]

将JSON转为CSV

public static string jsonStringToCSV(string content)
{
    var jsonContent = (JArray)JsonConvert.DeserializeObject(content);

    var csv = ServiceStack.Text.CsvSerializer.SerializeToCsv(jsonContent);
    return csv;
}

这不会给我提供CSV数据

在此输入图片描述

然后一些文件的分隔符可能是逗号或制表符,我想利用CSVHelper将CSV字符串动态转换为IEnumerable。

public static IEnumerable StringToList(string data, string delimiter, bool HasHeader)
{
    using (var csv = new CsvReader(new StringReader(data)))
    {
         csv.Configuration.SkipEmptyRecords = true;
         csv.Configuration.HasHeaderRecord = HasHeader;
         csv.Configuration.Delimiter = delimiter;

         var records = csv.GetRecords();
         return records;
     }
}

请您提供给我们所给出的错误或输出。 - Eminem
@Eminem 请查看Excel截图。 - Priyanka Rathee
我要求的是它实际给出的输出,而不是你期望它给出的输出。 - Eminem
抱歉,我以为那些是实际的值。 - Eminem
它似乎正在输出类型的属性?您能确认您的内容是否正确传递吗? - Eminem
显示剩余6条评论
7个回答

68

我能够通过使用Json.net将DeserializeObject转换为DataTable来解决这个问题,因此想发布自己的答案,但不会将其标记为已接受,如果有更好的方法,请告诉我。

将JSON字符串转换为DataTable

public static DataTable jsonStringToTable(string jsonContent)
        {
            DataTable dt = JsonConvert.DeserializeObject<DataTable>(jsonContent);
            return dt;
        }

生成CSV字符串

public static string jsonToCSV(string jsonContent, string delimiter)
        {
            StringWriter csvString = new StringWriter();
            using (var csv = new CsvWriter(csvString))
            {
                csv.Configuration.SkipEmptyRecords = true;
                csv.Configuration.WillThrowOnMissingField = false;
                csv.Configuration.Delimiter = delimiter;

                using (var dt = jsonStringToTable(jsonContent))
                {
                    foreach (DataColumn column in dt.Columns)
                    {
                        csv.WriteField(column.ColumnName);
                    }
                    csv.NextRecord();

                    foreach (DataRow row in dt.Rows)
                    {
                        for (var i = 0; i < dt.Columns.Count; i++)
                        {
                            csv.WriteField(row[i]);
                        }
                        csv.NextRecord();
                    }
                }
            }
            return csvString.ToString();
        }

Web API中最终用法

string csv = jsonToCSV(content, ",");

                HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
                result.Content = new StringContent(csv);
                result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
                result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "export.csv" };
                return result;

正是我想要达到的目标。运行得非常好! - marcus
它工作得很好吗?我的jsonStringToTable由于newtonsoft中的格式问题而崩溃了。 - stian
1
当我在NuGet库中搜索Json.NET时,结果窗口返回Newtonsoft.Json。我猜它是一样的。它已经安装在我的项目中,但CsvWriter似乎缺失。该项目正在使用.NET v4.6.2。有什么想法如何让它工作? - Victor_Tlepshev
4
CsvWriter 可以在另一个名为 CsvHelper 的包中找到 - https://github.com/JoshClose/CsvHelper,您可以使用 "Install-Package CsvHelper" 进行安装。 - Priyanka Rathee
1
当您的字段为Json对象时,该怎么办?反序列化为DataTable将会抛出错误。 - Avi Meltser
@Victor_Tlepshev - 就像Victor说的。 - KWallace

31

我不知道是否为您的问题报告解决方案已经太晚了。以防万一,如果您想探索使用开源库完成此任务,这里有一个选择

Cinchoo ETL使得使用几行代码将JSON转换为csv变得非常容易。

using (var r = new ChoJSONReader("sample.json"))
{
    using (var w = new ChoCSVWriter("sample.csv").WithFirstLineHeader())
    {
        w.Write(r);
    }
}

如需更多信息/源代码,请访问https://github.com/Cinchoo/ChoETL

Nuget包:

.NET Framework:

      Install-Package ChoETL.JSON

.NET Core:

      Install-Package ChoETL.JSON.NETStandard

示例代码: https://dotnetfiddle.net/T3u4W2

完全透明披露:本库作者为我自己。


18
明白。供您参考,这是一个开源库,展示如何使用它来解决问题。除此之外没有更多的内容。 - Cinchoo
1
我明白。我只是在说社区的看法。只要说明你与库的关系,就可以了。 - Nkosi
1
我安装了你的 Install-Package ChoETL,然后尝试添加其命名空间。但系统显示 reference missing 的错误。我已经清除了解决方案,但一切都徒劳无功。你能帮忙吗!! @RajN - Arsman Ahmad
发现包中存在不兼容的依赖关系。已进行修正,推送了新版本1.0.9。 - Cinchoo
2
这个库非常棒。它可以将嵌套的 JSON 层级解析成 CSV,捕获所有数据。 - user890332
显示剩余3条评论

7

最近我也遇到了同样的问题,并且我认为可以使用System.Dynamic.ExpandoObjectCsvHelper实现更加优雅的解决方案。这种方法的代码量更少,而且希望性能与DataTable相当或更好。

    public static string JsonToCsv(string jsonContent, string delimiter)
    {
        var expandos = JsonConvert.DeserializeObject<ExpandoObject[]>(jsonContent);

        using (var writer = new StringWriter())
        {
            using (var csv = new CsvWriter(writer))
            {
                csv.Configuration.Delimiter = delimiter;

                csv.WriteRecords(expandos as IEnumerable<dynamic>);
            }

            return writer.ToString();
        }
    }

1
我发现这个解决方案是最好的。 :-) - Varun
如果某些条目缺少某些值,则无法使其正常工作。 - Little geek

1
这段代码对我来说没问题:
3个函数(check,parse和aux)。
    private bool IsValidJson(string strInput)
    {
        try 
        { 
            if (string.IsNullOrWhiteSpace(strInput)) { return false; }
        
            strInput = strInput.Trim();

            if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || (strInput.StartsWith("[") && strInput.EndsWith("]"))) 
            {
                try
                {
                    _ = JToken.Parse(strInput);

                    return true;
                }
                catch
                {
                    return false;
                }
            }

            return false;
        }
        catch { throw; }
    }

    private string ParseJsonToCsv(string json)
    {
        try
        {
            XmlNode xml = JsonConvert.DeserializeXmlNode("{records:{record:" + json + "}}");

            XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(xml.InnerXml);

            DataSet dataSet = new DataSet(); dataSet.ReadXml(new XmlNodeReader(xmldoc));

            string csv = DTableToCsv(dataSet.Tables[0], ",");

            return csv;
        }
        catch { throw; }
    }

    private string DTableToCsv(DataTable table, string delimator)
    {
        try 
        { 
            var result = new StringBuilder();

            for (int i = 0; i < table.Columns.Count; i++)
            {
                result.Append(table.Columns[i].ColumnName);
                result.Append(i == table.Columns.Count - 1 ? "\n" : delimator);
            }

            foreach (DataRow row in table.Rows)
                for (int i = 0; i < table.Columns.Count; i++)
                {
                    result.Append(row[i].ToString());
                    result.Append(i == table.Columns.Count - 1 ? "\n" : delimator);
                }

            return result.ToString().TrimEnd(new char[] { '\r', '\n' });
        }
        catch { throw; }
    }

0
public void Convert2Json() 
        { 
            try 
            { 
                if (FileUpload1.PostedFile.FileName != string.Empty) 
                { 
                    string[] FileExt = FileUpload1.FileName.Split('.'); 
                    string FileEx = FileExt[FileExt.Length - 1]; 
                    if (FileEx.ToLower() == "csv") 
                    { 
                        string SourcePath = Server.MapPath("Resources//" + FileUpload1.FileName); 
                        FileUpload1.SaveAs(SourcePath); 
                        string Destpath = (Server.MapPath("Resources//" + FileExt[0] + ".json")); 

                        StreamWriter sw = new StreamWriter(Destpath); 
                        var csv = new List<string[]>(); 
                        var lines = System.IO.File.ReadAllLines(SourcePath); 
                        foreach (string line in lines) 
                            csv.Add(line.Split(',')); 
                        string json = new 
                            System.Web.Script.Serialization.JavaScriptSerializer().Serialize(csv); 
                        sw.Write(json); 
                        sw.Close(); 
                        TextBox1.Text = Destpath; 
                        MessageBox.Show("File is converted to json."); 
                    } 
                    else 
                    { 
                        MessageBox.Show("Invalid File"); 
                    } 

                } 
                else 
                { 
                    MessageBox.Show("File Not Found."); 
                } 
            } 
            catch (Exception ex) 
            { 
                MessageBox.Show(ex.Message); 
            } 
        }

你正在使用 line.Split(',') 这种方法,这不是一个好主意。最好使用 CSV 读取器。 - user890332

0
以下代码可以成功编译最新稳定版本的CsvHelper nuget包。
public static string JsonToCsv(string jsonContent, string delimeter)
        {
            var expandos = JsonConvert.DeserializeObject<ExpandoObject[]>(jsonContent);

            using (TextWriter writer = new StringWriter())
            {
                CsvConfiguration csvConfiguration = new CsvConfiguration(System.Globalization.CultureInfo.CurrentCulture);
                csvConfiguration.Delimiter = delimeter;
                using (var csv = new CsvWriter(writer, csvConfiguration))
                {
                    csv.WriteRecords((expandos as IEnumerable<dynamic>));
                }

                return writer.ToString();
            }
        }

-3
using System.Globalization;

using (var csv = new CsvWriter(csvString, CultureInfo.CurrentCulture)) {
  ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接