【问题标题】:Read and parse a Json File in C#在 C# 中读取和解析 Json 文件
【发布时间】:2012-10-29 03:39:39
【问题描述】:

我花了两天时间“花时间”处理代码示例等,试图将一个非常大的 JSON 文件读入 c# 中的一个数组,以便以后可以将其拆分为一个二维数组进行处理。

我遇到的问题是我找不到任何人在做我想做的事情的例子。这意味着我只是在编辑代码,希望能取得最好的结果。

我已经设法让一些工作:

  • 读取文件遗漏标头,仅将值读取到数组中。
  • 在数组的每一行放置一定数量的值。 (所以我 以后可以将其拆分为二维数组)

这是使用下面的代码完成的,但是在向数组中输入几行后它会导致程序崩溃。这可能与文件大小有关。

// If the file extension was a jave file the following 
// load method will be use else it will move on to the 
// next else if statement
if (fileExtension == ".json") 
{
    int count = 0;
    int count2 = 0;
    int inOrOut = 0;
    int nRecords=1; 
    JsonTextReader reader = new JsonTextReader(new StreamReader(txtLoaction.Text));
    string[] rawData = new string[5];
    while (reader.Read())
    {
        if (reader.Value != null)
            if (inOrOut == 1)
            {
                if (count == 6)
                {
                    nRecords++;
                    Array.Resize(ref rawData, nRecords);
                    //textBox1.Text += "\r\n";
                    count = 0;
                }
                rawData[count2] += reader.Value + ","; //+"\r\n"
                inOrOut = 0;
                count++;
                if (count2 == 500)
                {
                    MessageBox.Show(rawData[499]);
                }
            }
            else
            {
                inOrOut = 1;
            }
    } 
}

我正在使用的 JSON 的 sn-p 是:

[ 
    { "millis": "1000", 
      "stamp": "1273010254", 
      "datetime": "2010/5/4 21:57:34", 
      "light": "333", 
      "temp": "78.32", 
      "vcc": "3.54" }, 
] 

我需要这个 JSON 中的值。例如,我需要“3.54”,但我不希望它打印“vcc”。

我希望有人能告诉我如何读取 JSON 文件并只提取我需要的数据并将其放入数组或稍后我可以使用的东西放入数组中。

【问题讨论】:

标签: c# json parsing large-files


【解决方案1】:

使用Cinchoo ETL,一个开源库,解析非常大的JSON文件是迭代的,使用简单

1.动态方法: - 不需要 POCO 类

        string json = @"
[
  {
    ""millis"": ""1000"",
    ""stamp"": ""1273010254"",
    ""datetime"": ""2010/5/4 21:57:34"",
    ""light"": ""333"",
    ""temp"": ""78.32"",
    ""vcc"": ""3.54""
  },
  {
    ""millis"": ""2000"",
    ""stamp"": ""1273010254"",
    ""datetime"": ""2010/5/4 21:57:34"",
    ""light"": ""333"",
    ""temp"": ""78.32"",
    ""vcc"": ""3.54""
  }
] 
";
        
        using (var r = ChoJSONReader.LoadText(json))
        {
            foreach (var rec in r)
                Console.WriteLine(rec.Dump());
        }

小提琴样例:https://dotnetfiddle.net/mo1qvw

2。 POCO方法:

定义POCO类匹配json属性

public class Item
{
    public int Millis { get; set; }
    public string Stamp { get; set; }
    public DateTime Datetime { get; set; }
    public string Light { get; set; }
    public float Temp { get; set; }
    public float Vcc { get; set; }
}

然后使用解析器加载 JSON 如下

        string json = @"
[
  {
    ""millis"": ""1000"",
    ""stamp"": ""1273010254"",
    ""datetime"": ""2010/5/4 21:57:34"",
    ""light"": ""333"",
    ""temp"": ""78.32"",
    ""vcc"": ""3.54""
  },
  {
    ""millis"": ""2000"",
    ""stamp"": ""1273010254"",
    ""datetime"": ""2010/5/4 21:57:34"",
    ""light"": ""333"",
    ""temp"": ""78.32"",
    ""vcc"": ""3.54""
  }
] 
";
        
        using (var r = ChoJSONReader<Item>.LoadText(json))
        {
            foreach (var rec in r)
                Console.WriteLine(ChoUtility.Dump(rec));
        }

小提琴样例:https://dotnetfiddle.net/fRWu0w

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

【讨论】:

    【解决方案2】:

    有一种更简单的方法可以从文件或 Web 中获取 JSON: Json.Net.Curl

    安装包Json.Net.Curl

    // get JObject from local file system 
    var json = Json.Net.Curl.Get(@"data\JObjectUnitTest1.json");
    var json = await Json.Net.Curl.GetAsync(@"data\JObjectUnitTest1.json")
    
    
    // get JObject from Server  
    var json = await Json.Net.Curl.GetAsync("http://myserver.com/data.json");
    

    GitHub Project Nuget

    【讨论】:

      【解决方案3】:

      有一种 比 Json.Net 更快的解析 json 的方法。如果您使用的是 .net core 3.0 或更高版本,则可以使用System.Text.Json nuget 包进行序列化或反序列化。

      你需要添加:

      using System.Text.Json
      

      然后你可以序列化为:

      var jsonStr = JsonSerializer.Serialize(model);
      

      并反序列化为:

      var model = JsonSerializer.Deserialize(jsonStr);
      

      【讨论】:

      • 我认为您的第二点是序列化。
      【解决方案4】:

      .NET Core 的答案

      您可以只使用内置的System.Text.Json 而不是第三方Json.NET。为了促进重用,JSON 文件读取功能属于其自己的类,并且应该是通用的,而不是硬编码为特定类型 (Item)。这是一个完整的例子:

      using System;
      using System.IO;
      using System.Text.Json;
      using System.Threading.Tasks;
      
      namespace Project
      {
          class Program
          {
              static async Task Main()
              {
                  Item item = await JsonFileReader.ReadAsync<Item>(@"C:\myFile.json");
              }
          }
      
          public static class JsonFileReader
          {
              public static async Task<T> ReadAsync<T>(string filePath)
              {
                  using FileStream stream = File.OpenRead(filePath);
                  return await JsonSerializer.DeserializeAsync<T>(stream);
              }
          }
      
          public class Item
          {
              public int millis;
              public string stamp;
              public DateTime datetime;
              public string light;
              public float temp;
              public float vcc;
          }
      }
      

      或者,如果您更喜欢更简单/同步的东西:

      class Program
      {
          static void Main()
          {
              Item item = JsonFileReader.Read<Item>(@"C:\myFile.json");
          }
      }
      
      public static class JsonFileReader
      {
          public static T Read<T>(string filePath)
          {
              string text = File.ReadAllText(filePath);
              return JsonSerializer.Deserialize<T>(text);
          }
      }
      

      【讨论】:

      • 我尝试了您的解决方案,但 CSC 不希望 Main() 异步:错误 CS4009:“返回的 void 或 int 入口点不能是异步的”
      • @geriwald 抱歉,async Main 需要返回 Task,而不是 void。我更新了。
      【解决方案5】:
      string jsonFilePath = @"C:\MyFolder\myFile.json";
                  
      string json = File.ReadAllText(jsonFilePath);
      Dictionary<string, object> json_Dictionary = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(json);
      
      foreach (var item in json_Dictionary)
      {
          // parse here
      }
      

      【讨论】:

        【解决方案6】:

        使用Json.NET 让一切变得更简单如何?

            public void LoadJson()
            {
                using (StreamReader r = new StreamReader("file.json"))
                {
                    string json = r.ReadToEnd();
                    List<Item> items = JsonConvert.DeserializeObject<List<Item>>(json);
                }
            }
        
            public class Item
            {
                public int millis;
                public string stamp;
                public DateTime datetime;
                public string light;
                public float temp;
                public float vcc;
            }
        

        您甚至可以在不声明 Item 类的情况下获取值 dynamically

            dynamic array = JsonConvert.DeserializeObject(json);
            foreach(var item in array)
            {
                Console.WriteLine("{0} {1}", item.temp, item.vcc);
            }
        

        【讨论】:

        • @ChrisDevine 我希望您没有将路径设置为json。它必须是您文件的内容。
        • StreamReader("file.json") 需要 Stream 而不是字符串
        • 在 C# DotNet Core 中,使用: using (StreamReader r = File.OpenText("file.json"))
        • 对于那些不喜欢阅读其他答案的人来理解这个:这个解决方案需要 Json.net 包(Newtonsoft.Json)
        • 既然你有一个StreamReader,最好使用JsonTextReader直接从流中反序列化,如Can Json.NET serialize / deserialize to / from a stream?所示。不需要r.ReadToEnd()
        【解决方案7】:

        这段代码可以帮助你:

        string _filePath = Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory);
        
        JObject data = JObject.Parse(_filePath );
        

        【讨论】:

        • Parse 期望 json 内容为字符串,而不是文件路径
        【解决方案8】:

        这也可以通过以下方式完成:

        JObject data = JObject.Parse(File.ReadAllText(MyFilePath));
        

        【讨论】:

          【解决方案9】:

          基于@L.B. 的解决方案,(键入为Object 而不是Anonymous)VB 代码是

          Dim oJson As Object = JsonConvert.DeserializeObject(File.ReadAllText(MyFilePath))
          

          我应该提到,这对于构造不需要类型的 HTTP 调用内容非常快速且有用。使用Object 而不是Anonymous 意味着您可以在Visual Studio 环境中维护Option Strict On - 我讨厌关闭它。

          【讨论】:

            【解决方案10】:

            对于任何 JSON 解析,使用网站 http://json2csharp.com/(最简单的方法)将您的 JSON 转换为 C# 类,以将您的 JSON 反序列化为 C# 对象。

             public class JSONClass
             {
                    public string name { get; set; }
                    public string url { get; set; }
                    public bool visibility { get; set; }
                    public string idField { get; set; }
                    public bool defaultEvents { get; set; }
                    public string type { get; set; }        
             }
            

            然后使用 JavaScriptSerializer(来自 System.Web.Script.Serialization),以防您不想要任何第三方 DLL,如 newtonsoft。

            using (StreamReader r = new StreamReader("jsonfile.json"))
            {
               string json = r.ReadToEnd();
               JavaScriptSerializer jss = new JavaScriptSerializer();
               var Items = jss.Deserialize<JSONClass>(json);
            }
            

            然后您可以使用 Items.name 或 Items.Url 等获取您的对象。

            【讨论】:

            • 现在可以在VS中直接将json转成C#,Edit -> paste special -> Paste json as Classes
            【解决方案11】:

            自己做这件事是个糟糕的主意。使用Json.NET。如果他们有几个月的时间来解决这个问题,它已经比大多数程序员更好地解决了这个问题。至于您的特定需求,解析成数组等,请查看documentation,尤其是JsonTextReader。基本上,Json.NET 原生处理 JSON 数组,并将它们解析为字符串、整数或任何类型的类型,而无需您提示。 Here 是读者和作者基本代码用法的直接链接,因此您可以在学习使用它时在备用窗口中打开它。

            这是最好的:这次要偷懒并使用库,以便您永远解决这个常见问题。

            【讨论】:

            • 我正在使用 Json.net,但我不明白它是如何正常工作的。当我使用 JsonTextReader 将信息读取到文本框中时,我会得到每一位数据,还有标题等。我只想要标题中的值。我试图阅读 Json.NET 文档,但我没有发现它解释了一切足以让我以我想要的方式使用它
            • @ChrisDevine “Json 标头”?你指的是钥匙吗?如果您发布一个简短的(约 10-15 行)JSON sn-p 并准确指出您要提取的内容,也许这会更容易。
            • @ChrisDevine 我刚刚在您的问题中添加了您的评论,所以如果您可以删除上面的评论,那就太好了。
            • @ChrisDevine 另外,如果你能回答我对你的问题的评论,那也很棒。
            • @ChrisDevine 是的,我是说我把它放在你的问题中,所以这里不再需要。
            【解决方案12】:

            为了找到我正在使用的正确路径

               var pathToJson = Path.Combine("my","path","config","default.Business.Area.json");
               var r = new StreamReader(pathToJson);
               var myJson = r.ReadToEnd();
            
               // my/path/config/default.Business.Area.json 
               [...] do parsing here 
            

            Path.Combine 使用 Path.PathSeparator 并检查第一个路径的末尾是否已经有分隔符,因此它不会重复分隔符。此外,它还会检查要组合的路径元素是否包含无效字符。

            https://stackoverflow.com/a/32071002/4420355

            【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-08-10
            • 1970-01-01
            • 1970-01-01
            • 2020-08-01
            • 2021-03-21
            • 2010-10-13
            相关资源
            最近更新 更多