【问题标题】:Close a file after using it with JSON使用 JSON 后关闭文件
【发布时间】:2021-04-18 17:29:16
【问题描述】:

我发现该函数可以正确地用于 JSON 解析:

var objs = JObject.Load(new JsonTextReader(new StreamReader(JsonPath)))
                  .SelectTokens("*")
                  .Select(t => JsonConvert.DeserializeObject<Cars>(t.ToString()));

但它在使用后不会释放文件(所以我不能将它用于其他功能)...我尝试使用函数关闭,但似乎无法处理对象!

附:我已经检查了与该主题相关的previous open-one question,但没有人谈论如何访问对象文件,并且如果我们计算我有超过 1 个对象,那么问题似乎是不同的......猜想有人可以解释得更好它是如何工作的......

【问题讨论】:

  • 不要写这样的代码。该文件由文本阅读器保持打开状态。要关闭文本阅读器,您需要能够访问它。将所有代码放在一行中没有任何好处
  • JsonConvert.DeserializeObject&lt;Cars&gt;(t.ToString())) 有什么意义??? JSON 文件的实际内容是什么?如果你想反序列化到特定的类,直接使用反序列化器。
  • 感谢您的回复!我真的不知道......我需要承认......我在 c# 中很新,我只想获取 json 并读取它上面的所有字段......你有更好的代码吗建议我? (我在堆栈的另一个主题中找到它,我正在研究 json,我接受了它,它似乎工作......)
  • 您不能只编写代码并期望它能够工作。 JSON.NET 有大量的文档来展示如何解析或反序列化文件。每种情况下只有几行。同样,文件包含什么?
  • 当你开始喝威士忌、爱上橄榄并使用 DI 的时候会到来 :)

标签: c# json parsing streamreader


【解决方案1】:

来自 JSON.NET 站点 Read JSON from a File

// read JSON directly from a file
using (StreamReader file = File.OpenText(@"c:\videogames.json"))
using (JsonTextReader reader = new JsonTextReader(file))
{
    JObject o2 = (JObject)JToken.ReadFrom(reader);
}

虽然问题的代码做了一些不必要的事情 - 它尝试将已经反序列化的 JObject 序列化回 JSON,然后将其再次反序列化为 Car。为什么不将原始文件反序列化一次?

Deserialize JSON from a file 中的文档也对此进行了描述:

// deserialize JSON directly from a file
using (StreamReader file = File.OpenText(@"c:\movie.json"))
{
    JsonSerializer serializer = new JsonSerializer();
    Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
}

JSON 文档只能包含一个对象。如果文件内容如下所示:

{
    "Movies":[{
                  "Title":"abc"
              }, {

                  "Title":"abc"
              }]
}

根对象应包含一个 Movies 属性,该属性包含一个 Movie[] 数组:

class RootObjedt
{
    public Movie[] Movies{get;set;}
}

...

using (StreamReader file = File.OpenText(@"c:\movie.json"))
{
    JsonSerializer serializer = new JsonSerializer();
    var root = (Movie)serializer.Deserialize(file, typeof(RootObject));
    var movies=root.Movies;
}

【讨论】:

  • (实施前正在看,先谢谢各位的回复!我正在研究,完成后再回复)
  • hmm ..我在看它...如果我有多个对象会发生什么?在这种特殊情况下,我使用“汽车”类,并且 json 文件包含更多的一个对象。每个物体都是一辆特定的汽车!
  • @Zenekn JSON 不允许多个根对象。发布您的数据样本。目前只能猜测里面有什么。
  • 您是对的,感谢您的大力支持。那是我的 json:pastebin.com/nniFLYrm 那是我的课:pastebin.com/H4TrS6eJ
【解决方案2】:

我建议您异步读取 json 数据,因为此方法具有将流作为输入的重载,因此您可以读取两个代码字符串中的数据,如下所示:

ProjFolder\Program.cs

using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using StackOverflow.Models;

namespace StackOverflow
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var openStream = File.OpenRead(@"D:\Code\test.json");

            var result = await JsonSerializer.DeserializeAsync<Root>(openStream);

            // You need to get car2 Costo
            var costo = result.Car2.Costo;
        }
    }    
}

ProjFolder\Models\Root.cs

using System.Text.Json.Serialization;

namespace StackOverflow.Models
{
    public class Root
    {
        [JsonPropertyName("car1")]
        public Car Car1 { get; set; }

        [JsonPropertyName("car2")]
        public Car Car2 { get; set; }
    }
}

ProjFolder\Models\Car.cs

namespace StackOverflow.Models
{
    public class Car
    {
        public string CasaAutomobilistica { get; set; }
        public string Modello { get; set; }
        public string AnnoImmatricolazione { get; set; }
        public string Targa { get; set; }
        public int KM { get; set; }
        public bool Finanziamento { get; set; }
        public int Porte { get; set; }
        public int Costo { get; set; }
    }
}
{
    "car1": 
    {
        "CasaAutomobilistica": "Fiat",
        "Modello": "500",
        "AnnoImmatricolazione": "2017",
        "Targa": "AZ978AG",
        "KM": 120000,
        "Finanziamento" : true,
        "Porte" : 5,
        "Costo" : 6000
    },
    "car2":
    {
        "CasaAutomobilistica": "BMW",
        "Modello": "Serie 1",
        "AnnoImmatricolazione": "2019",
        "Targa": "BC978AG",
        "KM": 150000,
        "Finanziamento" : false,
        "Porte" : 3,
        "Costo" : 12000
    }
}

【讨论】:

  • 哦……太好了!加载完成后,我可以使用某种语句进行检查?
  • 其实你需要做的是正确编码你要反序列化的数据的模型。之后,您可以像使用简单对象、对象列表或 c# 中的任何其他内容一样使用它。如果是 IEnumerable(例如 List),则可以使用 Linq。如果你在谈论验证“数据是否反序列化”,那么如果出现问题,DeserializeAsync 会抛出异常,你只需要try catch 表达式来测试它。
  • 我尝试使用该代码,但是当您有超过 1 个对象时它似乎不起作用,而且我需要在另一个类中实现该任务,所以不能在主中调用它:(
  • 它可以使用所有有效的 jason 数据。如果不是,那么你的模型是错误的。你可以在你的问题中提供你想要反序列化的 JSON,我会用我的变体让它工作。
  • 是的,是的,我的意思是:当然是我的错,有些东西不起作用。我真的很感谢支持!那是我的课:pastebin.com/H4TrS6eJand 那是我的 json:pastebin.com/nniFLYrm
【解决方案3】:

首先,读取被 using 块包围的文件并进行 JSON 操作 最好将其放在单独的方法中,如下所示

private string readFile()
{
     string buffer = null;
     using (System.IO.FileStream stm = new 
         System.IO.FileStream("c:\\YourFile.txt",System.IO.FileMode.Open,  
         System.IO.FileAccess.Read, System.IO.FileShare.None))
         {
             using (System.IO.StreamReader rdr = new System.IO.StreamReader (stm))
             {
                            buffer=rdr.ReadToEnd();
             }
         }
      return buffer
}
private Object Deserialize(string content)
{
//do conversion here
}

【讨论】:

  • 这和 JSON 有什么关系? readFile 做了File.ReadAllText 做的事情
  • 最好将多个操作分开,例如:让我们考虑一下场景:如果文件内容不是JSON并且反序列化时出错。我们可能不知道由于文件操作(不存在,锁定)或 JSON 操作而导致的错误
  • 什么多重操作?如果您想将整个文件读入内存,File.ReadAllText 将完成这项工作。但是,对于大文件,这是一个 big 问题,这就是 StreamReader 首先存在的原因。当您可以在读取数据时对其进行解析,为什么要添加中间加载步骤
  • 操作一:文件读取,操作二:JSON反序列化
  • 将所有内容加载到内存中会导致需要进行垃圾回收的大对象。每次加载文件时,您都会分配 另一个 大对象。这在只运行一次的控制台应用程序中可能看起来并不重要,但 Web 服务器会很快耗尽所有可用 RAM
猜你喜欢
  • 1970-01-01
  • 2020-09-15
  • 2016-07-15
  • 1970-01-01
  • 2014-11-21
  • 2012-06-22
  • 2022-11-21
  • 2022-01-23
  • 1970-01-01
相关资源
最近更新 更多