【问题标题】:Parse JSON files using c#使用 C# 解析 JSON 文件
【发布时间】:2015-09-09 19:36:20
【问题描述】:

我编写了一个 c# 应用程序,它逐行读取 JSON 文件并从中写入 csv 文件。我为每种 csv 格式创建了模型文件,这些模型的对象在解析时被实例化,然后在最后写入 csv。

例如:如果输入文件名为 abc.json,则为 abc 创建并实例化对象,将其存储在 List 等数据结构中,然后将其写入最后的 csv。

JSON 文件

{
  "Computer ID": "1697343078",
  "Application Name": "Reporting Services Service",
  "Date": "8\/25\/2015",
  "Count": "1"
}

我要解析的代码如下:

using (System.IO.StreamReader sr = new System.IO.StreamReader(sFile, Encoding.UTF8))
while ((line = sr.ReadLine()) != null)
                        {
    if (line.Contains("Computer ID") && counter == 4)
            {
              string[] tokens = line.Split(':');
              if (tokens.Length >= 2)
              {
                  resourceID = reg.Replace(tokens[1], "");
              }
              counter = counter - 1;
              line = sr.ReadLine();
          }
}

由于输入文件中数据或其他字段的格式不一致,解析失败。代码抛出异常并且对该特定文件的解析完全失败。我希望我的代码拒绝解析的记录并继续解析文件中的其他记录,并最终为其生成一个 csv。

我希望它的行为如下, 逐行读取文件 如果解析时发生任何错误,请不要实例化该对象并继续解析该文件的其他行 将对象写入 csv

任何帮助将不胜感激。

【问题讨论】:

  • 请提供一个错误的 JSON 小示例,以及您想要的相应 CSV 输出。
  • 另外,解释错误是什么(它是一个异常,是不是别的什么......?)并显示与错误相关的代码......
  • 在问题帖子中而不是在评论区执行此操作。 ;)
  • @Anky,请在问题中添加您的附加信息。不要将它放在 cmets 中。如果您将有关问题的信息“到处”传播,就很难理解和理解您的问题;-)
  • 为什么不用真正的json解析器?

标签: c# json parsing csv


【解决方案1】:

您可以使用Json.NET 来解析您的 JSON 数据。为此,您需要:

  1. 定义与您的 JSON 对象对应的类。
  2. 如果出现DateTime 属性,请将其声明为nullable。如果遇到类似“未找到日期,因此未返回数据”的字符串,则可以将空值存储在属性中。
  3. 创建您自己的DateTimeConverter,在解析可为空的DateTime 时,尝试您可能遇到的各种日期时间格式。如果遇到无效格式,请返回 null 而不是抛出异常。
  4. 使用JsonConverterAttribute 将其应用于您的DateTime 属性。

因此,给定以下转换器:

public class DateTimeConverter : IsoDateTimeConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime?);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;

        var token = JToken.Load(reader);

        // For various JSON date formats, see
        // http://www.newtonsoft.com/json/help/html/DatesInJSON.htm

        // Try in JavaScript constructor format: new Date(1234656000000)
        if (token.Type == JTokenType.Constructor)
        {
            try
            {
                var result = token.ToObject<DateTime?>(JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = new JsonConverter[] { new JavaScriptDateTimeConverter() } }));
                if (result != null)
                    return result;
            }
            catch (JsonException)
            {
            }
        }

        // Try ISO format: "2009-02-15T00:00:00Z"
        if (token.Type == JTokenType.String)
        {
            try
            {
                var result = token.ToObject<DateTime?>(JsonSerializer.CreateDefault(new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.IsoDateFormat }));
                if (result != null)
                    return result;
            }
            catch (JsonException)
            {
            }
        }

        // Try Microsoft format: "\/Date(1234656000000)\/"
        if (token.Type == JTokenType.String)
        {
            try
            {
                var result = token.ToObject<DateTime?>(JsonSerializer.CreateDefault(new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat }));
                if (result != null)
                    return result;
            }
            catch (JsonException)
            {
            }
        }

        if (token.Type == JTokenType.String)
        {
            // Add other custom cases as required.
        }

        return null;
    }
}

您可以将它应用到您的班级,如下所示:

public class ComputerData
{
    [JsonProperty("Computer ID")]
    public string ComputerID { get; set; }

    [JsonProperty("Application Name")]
    public string ApplicationName { get; set; }

    [JsonConverter(typeof(DateTimeConverter))]
    public DateTime? Date { get; set; }

    public int Count { get; set; }
}

例如fiddle

【讨论】:

    【解决方案2】:

    您不需要 JSON 解析器。在解析数据格式不正确的行中的数据时,您需要尝试 catch 块来忽略异常。通过检查条件,您应该能够处理它。

    这可能是一个解决方案,我以前做过类似的事情,但最后我自己写了一个 JSON 解析器......

    实体类

     public class Info {
         public string ComputerID {get;set;}
         public string ApplicationName {get;set;}
         ...
     }
    

    用于解析文本并在解析行时忽略错误

     Info record = null;
     var recordSet = new List<Info>();
     using (System.IO.StreamReader sr = new System.IO.StreamReader(sFile, Encoding.UTF8))
     {
        while ((line = sr.ReadLine()) != null)
        {
             if (record==null){
                    record = new Info();
                    recordSet.Add(record)
             }
             try {
             } catch ( Exception e) {
              //You either log the data or ignore the exception here
             }
             //Check your property here, replace with your actual implementation here
             if (record.ComputerID!=null && record.ApplicationName!=null) {
                   record = null;
             }
    
        }
     }
    

    随着事情变得越来越复杂,您可能仍然需要一个解析器来处理它,但这真的取决于您的需求。

    【讨论】:

    • 这是个坏建议。解析 JSON 数据时,如果可能,您确实应该使用 JSON 解析器。尝试使用 Regex 或 Split 走捷径是在程序中引入细微错误的好方法。
    • @BrianRogers 好的。解析器获胜。但我不得不说,当 anky 要求一种方法来逐行读取文件时,如果解析时出现任何错误,请不要实例化该对象并继续解析该文件的其他行将对象写入 csv,你只需告诉他使用 JSON 解析器就可以了。解析器做了吗?
    • 很公平,您完全按照要求回答了这个问题。但我真的认为他的整个做法是错误的。他说他的数据存在格式不一致的问题,并且正在寻找一种方法来处理它们。使用解析器更容易做到这一点。请参阅@dbc 的答案以获得更好的方法。
    • @BrianRogers 我看不到答案会减少错误的空间。要编写一个稳定的程序,你不能只依赖第三个库。
    猜你喜欢
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 2020-06-22
    • 2020-05-07
    相关资源
    最近更新 更多