使用 C# 将 csv 文件转换为 json

本文关键字:转换 json 文件 csv 使用 | 更新日期: 2023-09-27 18:36:01

我想知道是否有人编写了一个实用程序来使用 C# 将 CSV 文件转换为 Json。从之前关于堆栈溢出的问题中,我知道这个不错的实用程序 - https://github.com/cparker15/csv-to-json,目前我计划参考它,但现有的 C# 实现将非常有帮助!谢谢!

使用 C# 将 csv 文件转换为 json

如果你可以使用System.Web.Extensions,这样的事情可以工作:

var csv = new List<string[]>(); // or, List<YourClass>
var lines = System.IO.File.ReadAllLines(@"C:'file.txt");
foreach (string line in lines)
    csv.Add(line.Split(',')); // or, populate YourClass          
string json = new 
    System.Web.Script.Serialization.JavaScriptSerializer().Serialize(csv);

您可能对 csv 文件有更复杂的解析要求,并且您可能有一个封装一行数据的类,但关键是一旦您拥有一组行,您就可以使用一行代码序列化为 JSON。

Cinchoo ETL - 一个开源库,只需几行代码即可轻松将CSV转换为JSON。

对于示例 CSV:

Id, Name, City
1, Tom, NY
2, Mark, NJ
3, Lou, FL
4, Smith, PA
5, Raj, DC

示例代码,

string csv = @"Id, Name, City
1, Tom, NY
2, Mark, NJ
3, Lou, FL
4, Smith, PA
5, Raj, DC
";
StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(csv)
    .WithFirstLineHeader()
    )
{
    using (var w = new ChoJSONWriter(sb))
        w.Write(p);
}
Console.WriteLine(sb.ToString());

输出 JSON:

[
 {
  "Id": "1",
  "Name": "Tom",
  "City": "NY"
 },
 {
  "Id": "2",
  "Name": "Mark",
  "City": "NJ"
 },
 {
  "Id": "3",
  "Name": "Lou",
  "City": "FL"
 },
 {
  "Id": "4",
  "Name": "Smith",
  "City": "PA"
 },
 {
  "Id": "5",
  "Name": "Raj",
  "City": "DC"
 }
]

样品小提琴:https://dotnetfiddle.net/pclnsT

查看代码项目文章以获取更多帮助。

更新:如果您的 CSV 文件有重复的列名称或没有名称,请使用以下步骤生成 JSON 文件

string csv = @"Id, Name, 
1, Tom, NY
2, Mark, NJ
3, Lou, FL
4, Smith, PA
5, Raj, DC
";
StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(csv)
    .WithField("Id", position: 1)
    .WithField("Name", position: 2)
    .WithField("City", position: 3)
    .WithFirstLineHeader(true)
    )
{
    using (var w = new ChoJSONWriter(sb))
        w.Write(p);
}
Console.WriteLine(sb.ToString());

样品小提琴:https://dotnetfiddle.net/pP5Du6

免责声明:我是这个库的作者。

我使用字典并使用Newtonsoft返回json

public string ConvertCsvFileToJsonObject(string path) 
{
    var csv = new List<string[]>();
    var lines = File.ReadAllLines(path);
    foreach (string line in lines)
        csv.Add(line.Split(','));
    var properties = lines[0].Split(',');
    var listObjResult = new List<Dictionary<string, string>>();
    for (int i = 1; i < lines.Length; i++)
    {
        var objResult = new Dictionary<string, string>();
        for (int j = 0; j < properties.Length; j++)
            objResult.Add(properties[j], csv[i][j]);
        listObjResult.Add(objResult);
    }
    return JsonConvert.SerializeObject(listObjResult); 
}
Install Nuget package NewtonSoft.Json
Add reference dll Microsoft.VisualBasic
using System.Linq;
using Newtonsoft.Json;
using Microsoft.VisualBasic.FileIO;
using System.IO;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Project
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            string CSVpath = @"D:'New Folder'information.csv";
            string analyticsData = ReadFile(CSVpath);
        }
        private static string ReadFile(string filePath)
        {
            string payload = "";
            try
            {
                if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath) && Path.GetExtension(filePath).Equals(".csv", StringComparison.InvariantCultureIgnoreCase))
                {
                    string[] lines = File.ReadAllLines(filePath);
                    if (lines != null && lines.Length > 1)
                    {
                        var headers = GetHeaders(lines.First());
                        payload = GetPayload(headers, lines.Skip(1));
                    }
                }
            }
            catch (Exception exp)
            {
            }
            return payload;
        }
        private static IEnumerable<string> GetHeaders(string data)
        {
            IEnumerable<string> headers = null;
            if (!string.IsNullOrWhiteSpace(data) && data.Contains(','))
            {
                headers = GetFields(data).Select(x => x.Replace(" ", ""));
            }
            return headers;
        }
        private static string GetPayload(IEnumerable<string> headers, IEnumerable<string> fields)
        {
            string jsonObject = "";
            try
            {
                var dictionaryList = fields.Select(x => GetField(headers, x));
                jsonObject = JsonConvert.SerializeObject(dictionaryList);
            }
            catch (Exception ex)
            {
            }
            return jsonObject;
        }
        private static Dictionary<string, string> GetField(IEnumerable<string> headers, string fields)
        {
            Dictionary<string, string> dictionary = null;
            if (!string.IsNullOrWhiteSpace(fields))
            {
                var columns = GetFields(fields);
                if (columns != null && headers != null && columns.Count() == headers.Count())
                {
                    dictionary = headers.Zip(columns, (x, y) => new { x, y }).ToDictionary(item => item.x, item => item.y);
                }
            }
            return dictionary;
        }
        public static IEnumerable<string> GetFields(string line)
        {
            IEnumerable<string> fields = null;
            using (TextReader reader = new StringReader(line))
            {
                using (TextFieldParser parser = new TextFieldParser(reader))
                {
                    parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); fields = parser.ReadFields();
                }
            }
            return fields;
        }
    }
}

依赖于Newtonsoft.Json,这是一个给定CSV行数组的辅助方法,第一个是标头。

    public static IEnumerable<JObject> CsvToJson(IEnumerable<string> csvLines)
    {
        var csvLinesList = csvLines.ToList();
        var header = csvLinesList[0].Split(',');
        for (int i = 1; i < csvLinesList.Count; i++)
        {
            var thisLineSplit = csvLinesList[i].Split(',');
            var pairedWithHeader = header.Zip(thisLineSplit, (h, v) => new KeyValuePair<string, string>(h, v));
            yield return new JObject(pairedWithHeader.Select(j => new JProperty(j.Key, j.Value)));
        }
    }

我使用ChoETL:

using ChoETL;
using System.IO;
public class FromCSVtoJSON
{
    public FromCSVtoJSON()
    {
    }
    public void convertFile(string inputFile, string outputFile)
    {
        using (var writer = new ChoJSONWriter(outputFile))
        {
            using (var reader = new ChoCSVReader(inputFile).WithFirstLineHeader())
            {
                writer.Write(reader);
            }
        }
    }
}

从同一个 SO 答案中,有一个指向这篇文章的链接。

CsvToJson 扩展方法

/// <summary>
/// Converts a CSV string to a Json array format.
/// </summary>
/// <remarks>First line in CSV must be a header with field name columns.</remarks>
/// <param name="value"></param>
/// <returns></returns>
public static string CsvToJson(this string value)
{
    // Get lines.
    if (value == null) return null;
    string[] lines = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
    if (lines.Length < 2) throw new InvalidDataException("Must have header line.");
    // Get headers.
    string[] headers = lines.First().SplitQuotedLine(new char[] { ',' }, false);
    // Build JSON array.
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("[");
    for (int i = 1; i < lines.Length; i++)
    {
        string[] fields = lines[i].SplitQuotedLine(new char[] { ',', ' ' }, true, '"', false);
        if (fields.Length != headers.Length) throw new InvalidDataException("Field count must match header count.");
        var jsonElements = headers.Zip(fields, (header, field) => string.Format("{0}: {1}", header, field)).ToArray();
        string jsonObject = "{" + string.Format("{0}", string.Join(",", jsonElements)) + "}";
        if (i < lines.Length - 1)
            jsonObject += ",";
        sb.AppendLine(jsonObject);
    }
    sb.AppendLine("]");
    return sb.ToString();
}

在上述扩展中调用的某些方法似乎存在问题(请参阅原始博客文章的评论),但它应该可以让您大部分时间到达那里。

编辑 这是关于拆分 CSV 行的另一个答案。您可以使用建议的正则表达式解决方案之一来创建自己的SplitQuotedLine方法:

public static string SplitQuotedLine(this string value, char separator, bool quotes) {
    // Use the "quotes" bool if you need to keep/strip the quotes or something...
    var s = new StringBuilder();
    var regex = new Regex("(?<=^|,)('"(?:[^'"]|'"'")*'"|[^,]*)");
    foreach (Match m in regex.Matches(value)) {
        s.Append(m.Value);
    }
    return s.ToString();
}

我没有测试上述内容,所以如果我犯了任何错误,请原谅我。

此外,Zip 似乎是一种 LINQ 扩展方法,因此可以解决这个问题。

这是我

的..它可以解析几个世纪以来的 9k CSV 记录。大声笑

class CSVTOJSON
{
    public string ConvertToJSON()
    {
        string json = string.Empty;
        string csv = string.Empty;
        using (StreamReader reader = new StreamReader("data.csv"))
        {
            csv = reader.ReadToEnd();
        }
        string[] lines = csv.Split(new string[] { "'n" }, System.StringSplitOptions.None);
        if (lines.Length > 1)
        {
            // parse headers
            string[] headers = lines[0].Split(',');
            StringBuilder sbjson = new StringBuilder();
            sbjson.Clear();
            sbjson.Append("[");
            // parse data
            for (int i = 1; i < lines.Length; i++)
            {
                if (string.IsNullOrWhiteSpace(lines[i])) continue;
                if (string.IsNullOrEmpty(lines[i])) continue;
                sbjson.Append("{");
                string[] data = lines[i].Split(',');
                for (int h = 0; h < headers.Length; h++)
                {
                    sbjson.Append(
                        $"'"{headers[h]}'": '"{data[h]}'"" + (h < headers.Length - 1 ? "," : null)
                    );
                }
                sbjson.Append("}" + (i < lines.Length - 1 ? "," : null));
            }
            sbjson.Append("]");
            json = sbjson.ToString();
        }
        return json;
    }
}

但它有效。

控制台日志:

Converting CSV to JSON
CSV has 9486 data
Total duration converting CSV to JSON: 00:00:00.0775373

bc3tech 对解决方案的微小变化,即避免外部依赖(在 Newtonsoft.Json 上),而是使用 System.Text.Json(dotnet core 3+)

public static IEnumerable<string> CsvToJson(string fileName, char delim = '|')
{
    var lines = File.ReadLines(fileName); 
    var hdr = new List<string>(lines.First().Trim().Split(delim));
    foreach (var l in lines.Skip(1).Where(l => (l.Trim() != String.Empty))) 
    {
        var val = l.Trim().Split(delim);
        var ds = hdr.Zip(val, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);
        yield return JsonSerializer.Serialize(ds);
    }
}

我可以看到大多数人只是简单地假设解析CSV文件只是在每列之间拆分逗号分隔符,但以下格式仍然是有效的CSV

"aaa","bbb","ccc"
"z, z",yyy,xxx

Microsoft.VisualBasic.FileIO中隐藏了一个很好的类,可以正确处理CSV文件格式。我将其与 JSON.NET 想出的解决方案结合起来。

   public static string? CsvToJson(string input, string delimiter)
   {
        using (TextFieldParser parser = new TextFieldParser(
                 new MemoryStream(Encoding.UTF8.GetBytes(input))))
        {
            parser.Delimiters = new string[] { delimiter };
            string[]? headers = parser.ReadFields();
            if (headers == null) return null;
            string[]? row;
            string comma = "";
            var sb = new StringBuilder((int)(input.Length * 1.1));
            sb.Append("[");
            while ((row = parser.ReadFields()) != null)
            {
                var dict = new Dictionary<string, object>();
                for (int i = 0; row != null && i < row.Length; i++)
                    dict[headers[i]] = row[i];
                var obj = JsonConvert.SerializeObject(dict);
                sb.Append(comma + obj);
                comma = ",";
            }
            return sb.Append("]").ToString();
        }
    }

用法

var str = @"Header1,""Header,,2 "",Data3
1,444.00, ""Liang, Jerry""
0,""5,550"",Jerry
";
var json = CsvToJson(str, ",");

结果

[
  {
    "Header1": "1",
    "Header,,2": "444.00",
    "Data3": "Liang, Jerry"
  },
  {
    "Header1": "0441",
    "Header,,2": "5,550",
    "Data3": "Jerry"
  }
]

我寻找这个问题的答案,最后我使用字典解决了它

public static void CreateJsonFromCSV()
{
    string path = "C:''Users''xx''xx''xx''xx''lang.csv";
    string textFilePath = path;
    const Int32 BufferSize = 128;
    using (var fileStream = File.OpenRead(textFilePath))
    using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize))
    {
        String line;
        Dictionary<string, string> jsonRow = new Dictionary<string, string>();
        while ((line = streamReader.ReadLine()) != null)
        {
            string[] parts = line.Split(',');
            string key_ = parts[0];
            string value = parts[1];

            if (!jsonRow.Keys.Contains(key_))
            {
                jsonRow.Add(key_, value );
            }
        }
        var json = new JavaScriptSerializer().Serialize(jsonRow);
        string path_ = "C:''XX''XX''XX''XX''XX.csv";
        File.WriteAllText(path_, json);
    }
} 

在解析大型 csv 文件之前,请确保在 web.config 中添加以下内容。

 <system.web.extensions>
       <scripting>
           <webServices>
               <jsonSerialization maxJsonLength="50000000"/>
           </webServices>
       </scripting>
   </system.web.extensions>

试试这个:

 StreamReader sr = new StreamReader(filePath);
 while ((line = sr.ReadLine()) != null)
 {
      //Console.WriteLine(line);
      string[] csv = line.Split(',');
      var dictionary = new Dictionary<string, string>();
      dictionary.Add("dispatching_base_number",csv[0]);
      dictionary.Add("available_vehicles", csv[1]);
      dictionary.Add("vehicles_in_trips", csv[2]);
      dictionary.Add("Cancellations", csv[3]);
      string jsonN = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(dictionary);
      Console.WriteLine("Sending message: {0}",jsonN);
 }

试试这个并将CSV转换为JSON对象:

public static List<object> CsvToJson( string body, string[] column ) {
    if ( string.IsNullOrEmpty( body ) ) return null;
    string[] rowSeparators = new string[] { "'r'n" };
    string[] rows = body.Split( rowSeparators, StringSplitOptions.None );
    body = null;
    if ( rows == null || ( rows != null && rows.Length == 0 ) ) return null;
    string[] cellSeparator = new string[] { "," };
    List<object> data = new List<object>( );
    int clen = column.Length;
    rows.Select( row => {
        if ( string.IsNullOrEmpty( row ) ) return row;
        string[] cells = row.Trim( ).Split( cellSeparator, StringSplitOptions.None );
        if ( cells == null ) return row;
        if ( cells.Length < clen ) return row;
        Dictionary<object, object> jrows = new Dictionary<object, object>( );
        for ( int i = 0; i < clen; i++ ) {
            jrows.Add( column[i], cells[i]?.Trim( ) );
        }
        data.Add( jrows );
        return row;
    } ).ToList( );
    rowSeparators = null; rows = null;
    cellSeparator = null;
    return data;
}
var data = CsvToJson("csv_input_str", new string[]{ "column_map" })
string jsonStr = new JavaScriptSerializer { MaxJsonLength = int.MaxValue }.Serialize( data );

首先,将 csv 文件加载到数据表中,并将其序列化为 Json 文档。它使用OLEDB提供程序,可以明智地解析csv,

由 Jim Scott 提供,https://stackoverflow.com/a/1050278/6928056

由K_B提供,https://stackoverflow.com/a/2979938/6928056

using System.Data;
using System.Data.OleDb;
using System.Globalization;
using System.IO;
using Newtonsoft.Json;
static string ConvertCsvToJson(string path, bool isFirstRowHeader)
{
    string header = isFirstRowHeader ? "Yes" : "No";
    string pathOnly = Path.GetDirectoryName(path);
    string fileName = Path.GetFileName(path);
    string sql = @"SELECT * FROM [" + fileName + "]";
    using(OleDbConnection connection = new OleDbConnection(
              @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + pathOnly + 
              ";Extended Properties='"Text;HDR=" + header + "'""))
    using(OleDbCommand command = new OleDbCommand(sql, connection))
    using(OleDbDataAdapter adapter = new OleDbDataAdapter(command))
    {
        var dataTable = new DataTable();
        dataTable.Locale = CultureInfo.CurrentCulture;
        adapter.Fill(dataTable);
        return JsonConvert.SerializeObject(dataTable, Formatting.Indented);
    }
}

将平面 csv 文件转换为简单 JSON 格式对象的集合的简单方法。适用于标题行位于第一行的文件。这种方法的一部分是在SO的其他地方找到的。添加对 Microsoft.VisualBasic 的引用。

using Microsoft.VisualBasic.FileIO;
public static StringBuilder ReadCsv()
    {
        var path = @"X:'...'input.csv";
        using (TextFieldParser csvParser = new TextFieldParser(path))
        {
            csvParser.CommentTokens = new string[] { "#" };
            //Remember to use your own separator
            csvParser.SetDelimiters(new string[] { ";" });
            csvParser.HasFieldsEnclosedInQuotes = false;
            StringBuilder json = new StringBuilder();
            string[] colNames = new string[0];
            string[] fields = new string[0];
            json.Append("[");
            int counter = 0;
            while (!csvParser.EndOfData)
            {
                if (counter == 0)
                {
                    //Read properies' names
                    colNames = csvParser.ReadFields();
                    counter++;
                    Console.WriteLine($"{colNames.Length} columns detected!");
                }
                else
                {
                    // Read current line fields, pointer moves to the next line.
                    // Read the properties' values
                    fields = csvParser.ReadFields();
                    json.Append("{");
                    for (int i = 0; i < colNames.Length; i++)
                    {
                        json.Append($"'"{colNames[i]}'":{TryParse(fields[i])}");
                        if (i != colNames.Length - 1)
                        {
                            json.Append(",");
                        }
                    }
                    json.Append("},");
                    Console.WriteLine($"Writing record nr.: {counter}");
                    counter++;
                }
            }
            json.Length--; //Remove trailing comma
            json.Append("]");
            return json;
        }
    }
string TryParse(string s)
    {
        if (string.IsNullOrEmpty(s)) return "null";
        //Remember to set your decimal character here!
        if (s.Contains('.'))
        {
            double dResult;
            //This works on my computer, could be different on your machine
            if (double.TryParse(s, NumberStyles.AllowDecimalPoint,
                                CultureInfo.InvariantCulture, out dResult))
                return dResult.ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            int intResult;
            if (int.TryParse(s, out intResult))
                return intResult.ToString(CultureInfo.InvariantCulture);
        }
        return "'"" + s + "'"";
    }
<小时 />

这应该会给你一个简单的 json 对象列表。

如果您正在寻找仅限 C# 的解决方案,这可能适合您。我最近面临同样的问题,并创建了这种方法来克服。

public static string ConvertToJsonStructure(string csvDataAsString, char delimiter = ',', bool hasHeaders = true)
    {
        var output = string.Empty;
        if (string.IsNullOrEmpty(csvDataAsString))
            return "{}";
        var rows = csvDataAsString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
        var headers = hasHeaders ? rows[0].Split(delimiter) : null;
        var colCount = headers?.Length;
        var jsonStart = "{";
        var jsonEnd = "}";
        if (rows.Length > (1 + (hasHeaders ? 1 : 0)))
        {
            jsonStart = "[";
            jsonEnd = "]";
        }
        output = output + jsonStart;
        int startIndex = hasHeaders ? 1 : 0;
        for (int i = startIndex; i < rows.Length; i++)
        {
            var cols = rows[i].Split(delimiter);
            if (colCount == null)
                colCount = cols.Length;
            var tempJson = "{";
            for (int j = 0; j < colCount.Value; j++)
            {
                if (hasHeaders)
                    tempJson = tempJson + $"'"{headers[j]}'":";
                var isNumber = Regex.IsMatch(cols[j], @"^'d + $");
                var val = isNumber ? cols[j] : $"'"{cols[j]}'"";
                tempJson = tempJson + val;
                if (j < colCount.Value - 1)
                    tempJson = tempJson + ",";
            }
            tempJson = tempJson + "}";
            if (i < rows.Length - 1)
                tempJson = tempJson + ",";
            output = output + tempJson;
        }
        output = output + jsonEnd;
        return output;
    }
}

您需要将内容作为字符串传递给此方法,您可以执行类似操作来读取您的csv

var csvAsString = File.ReadAllText("TestCsv.csv");
        var result = CsvToJson.ConvertToJsonStructure(csvAsString);
出于您在

所有这些答案中看到的无数原因,请站在巨人的肩膀上并使用 Csv 解析 nuget 包提取数据,然后使用内置序列化程序将其序列化为 JSON。根本没有理由手掷这个。