# Gson - `JsonReader`

> 原文： [https://howtodoinjava.com/gson/jsonreader-streaming-json-parser/](https://howtodoinjava.com/gson/jsonreader-streaming-json-parser/)

了解如何使用 Gson `JsonReader`类，该类是基于请求的流式 JSON 解析器。 它有助于将 JSON 作为令牌流读取。

## 1\. `JsonReader`

*   `JsonReader`是流 JSON 解析器，并且是**拉式解析器**的示例。 推送解析器解析 JSON 令牌并将其推送到事件处理器中。
*   它有助于读取 JSON（[RFC 7159](https://www.ietf.org/rfc/rfc7159.txt)）编码的值作为令牌流。
*   它读取字面值（字符串，数字，布尔值和`null`）以及对象和数组的开始和结束定界符。
*   令牌以**深度优先顺序**遍历，与 JSON 文档中出现的顺序相同。

> 阅读更多： [XML](https://howtodoinjava.com/xml/sax-parser-read-xml-example/) 的流解析器

## 2.令牌

在流模式下，每个 JSON 数据都被视为一个单独的令牌。 当我们使用`JsonReader`处理它时，每个令牌将被顺序处理。 例如，

```java
{
	"name":"Lokesh"
}

```

在使用`JsonReader`进行解析时，上述 JSON 将生成 4 个令牌：

*   令牌 1 = `{`
*   令牌 2 = `name`
*   令牌 3 = `Lokesh`
*   令牌 4 = `}`

## 3.如何创建 GSON `JsonReader`

我们可以使用它的简单构造器创建一个`JsonReader`实例，该实例接受[`java.io.Reader`](https://docs.oracle.com/javase/10/docs/api/java/io/Reader.html)类型的输入流。

```java
String json = "{}";
JsonReader jsonReader = new JsonReader( new StringReader(json) );

```

我们可以根据 JSON 流的来源使用以下阅读器之一：

*   `BufferedReader`
*   `LineNumberReader`
*   `CharArrayReader`
*   `InputStreamReader`
*   `FileReader`
*   `FilterReader`
*   `PushbackReader`
*   `PipedReader`
*   `StringReader`

## 4.读取 JSON 流

在创建包装了有效 JSON 源的`JsonReader`之后，我们可以开始对流令牌进行迭代并查看令牌值。

以下是在令牌上使用`JsonReader`读取简单 JSON 的示例。

```java
import java.io.IOException;
import java.io.StringReader;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

public class Main 
{
	public static void main(String[] args) throws Exception 
	{

		String json = "{'id': 1001,'firstName': 'Lokesh','lastName': 'Gupta','email': null}";

		JsonReader jsonReader = new JsonReader(new StringReader(json));
		jsonReader.setLenient(true);

		try 
		{
			while (jsonReader.hasNext()) 
			{
				JsonToken nextToken = jsonReader.peek();

				if (JsonToken.BEGIN_OBJECT.equals(nextToken)) {

					jsonReader.beginObject();

				} else if (JsonToken.NAME.equals(nextToken)) {

					String name = jsonReader.nextName();
					System.out.println("Token KEY >>>> " + name);

				} else if (JsonToken.STRING.equals(nextToken)) {

					String value = jsonReader.nextString();
					System.out.println("Token Value >>>> " + value);

				} else if (JsonToken.NUMBER.equals(nextToken)) {

					long value = jsonReader.nextLong();
					System.out.println("Token Value >>>> " + value);

				} else if (JsonToken.NULL.equals(nextToken)) {

					jsonReader.nextNull();
					System.out.println("Token Value >>>> null");

				} else if (JsonToken.END_OBJECT.equals(nextToken)) {

					jsonReader.endObject();

				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			jsonReader.close();
		}
	}
}

```

```java
Token KEY >>>> id
Token Value >>>> 1001

Token KEY >>>> firstName
Token Value >>>> Lokesh

Token KEY >>>> lastName
Token Value >>>> Gupta

Token KEY >>>> email
Token Value >>>> null

```

在上面的示例中：

*   `JsonReader`的`hasNext()`方法如果有更多令牌，则返回`true`。
*   `peek()`方法返回下一个 JSON 令牌，但不移至下一个。
*   随后，多次调用`peek()`将返回相同的 JSON 令牌。
*   可以使用`JsonToken`类的常量检查返回令牌的类型。
*   使用`beginArray()`和`endArray()`方法检查数组的左括号`'['`和`']'`。
*   使用`beginObject()`和`endObject()`方法检查对象的左括号`'{'`和`'}'`。

令牌的密钥的类型为`JsonToken.NAME`。 使用`nextName()`方法获取密钥名称。

*   确定令牌类型后，使用`nextLong()`，`nextString()`和`nextInt()`等方法获取令牌的值。
*   可以使用`nextNull()`或`skipValue()`使用空字面值。
*   所有`next....()`方法都返回当前令牌的值，并将内部指针移到下一个。
*   当遇到未知名称时，严格的解析器应该失败，并带有异常。 宽松解析器应调用`skipValue()`来递归地跳过该值的嵌套令牌，否则可能会发生冲突。

将有关 Gson `JsonReader`的问题交给我。

学习愉快！

参考：

[Gson 用户指南](https://github.com/google/gson)

[`JsonReader` Java Doc](https://static.javadoc.io/com.google.code.gson/gson/2.8.5/com/google/gson/stream/JsonReader.html)