使用 JsonTextReader 读取 JSON 会引发错误

Posted

技术标签:

【中文标题】使用 JsonTextReader 读取 JSON 会引发错误【英文标题】:Reading JSON using a JsonTextReader throws an error 【发布时间】:2017-10-12 10:58:19 【问题描述】:

我正在尝试从数据库中读取存储为字符串的 JSON 数据,我需要以不同的方式转换数据。我看到 JSON.NET 在内部从 JsonTextReader 抛出错误。我试图通过直接使用以下代码来重现该错误。这段代码有什么问题?

var rs = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader("'1':'2'"));
rs.ReadAsString();

它会抛出一个错误:

解析值时遇到意外字符:。路径'',第 1 行,位置 1。

【问题讨论】:

【参考方案1】:

您收到错误是因为您错误地使用了JsonTextReader

JsonTextReader 类将 JSON 字符串视为一系列“令牌”,一次读取一个。可能的令牌由JsonToken 枚举定义,包括StartObjectStartArrayPropertyNameStringIntegerBooleanNullEndObject 和@987636@3 到4举几个例子。

当您调用ReadAsString 时,它会将阅读器推进到下一个标记并尝试将该标记解释为字符串。在您的 JSON 中,第一个标记不是字符串;它是StartObject(对应于左大括号)。 ReadAsString 没有预料到这一点,所以它会抛出一个错误。

ReadAs... 方法仅在您已经预先知道阅读器遇到的下一个标记将是特定类型(例如字符串)的情况下才有用。如果事先不知道 JSON 结构,想用JsonTextReader 来扫描,可以循环调用Read 方法,直到返回false。每个Read 调用都会将阅读器推进到下一个令牌并设置TokenTypeValue 属性。然后您可以检查TokenType 以确定如何处理Value

这是一个简单的示例,它使用JsonTextReader 循环遍历 JSON 并在每个步骤中转储出 TokenTypeValue。这应该让您很好地了解读者如何看待您的 JSON:

JsonTextReader rs = new JsonTextReader(new StringReader("'1':'2'"));

Console.WriteLine("TokenType     Value");
Console.WriteLine("------------  ------");
while (rs.Read())

    Console.WriteLine(string.Format("0,-12  1", 
        rs.TokenType.ToString(),
        rs.Value != null ? rs.Value.ToString() : "(null)"));

小提琴:https://dotnetfiddle.net/nxWd1X

这是输出:

TokenType     Value
------------  ------
StartObject   (null)
PropertyName  1
String        2
EndObject     (null)

请记住,JsonTextReader 是一个用于解析 JSON 的非常低级的 API,除了最简单的 JSON 结构之外,它可能会变得难以使用。如果您的 JSON 具有众所周知的结构,则可能更容易定义匹配的类(或一组类)并使用 JsonConvert.DeserializeObject<T> 反序列化为该类。例如:

public class RootObject

    [JsonProperty("1")]
    public string One  get; set; 


var root = JsonConvert.DeserializeObject<RootObject>("'1':'2'");

Console.WriteLine(root.One);   // 2

或者,如果您的 JSON 结构是动态的或不为人所知,您可以改用 LINQ-to-JSON API (JObjects)。例如:

var obj = JObject.Parse("'1':'2'");
foreach (JProperty prop in obj.Properties())

    Console.WriteLine(prop.Name + ": " + prop.Value);   // 1: 2

【讨论】:

谢谢。我已经想通了。我的意图是将完整的 JSON 作为字符串读取并反序列化。我必须为接口实现一个通用Task&lt;T&gt; Get&lt;T&gt;(key) 方法,其中实际实现需要从将数据存储为JSON 的数据存储中获取数据,主要是JSON 格式的序列化对象,但有时我也必须返回读取字符串,其中 T 是字符串,我为此使用了 JSONConvert.DeserilaizeObject&lt;T&gt;(string),这就是我得到这个错误的地方。

以上是关于使用 JsonTextReader 读取 JSON 会引发错误的主要内容,如果未能解决你的问题,请参考以下文章

c# JsonReader读取json字符串

如何反序列化 JSONP 响应(最好使用 JsonTextReader 而不是字符串)?

如何反序列化 JSONP 响应(最好使用 JsonTextReader 而不是字符串)?

StreamReader 和 JsonTextReader 的反序列化不起作用

如何在JSON.NET中unescape unicode

如何使用 Dojo 读取 JSON 文件