Прочитать файл json c
В процессе написания программы EColor появилась задача, в которой было необходимо каким-то образом уведомлять пользователя о том, что вышла новая версия программы. Решением этой задачи стало наличие JSON файла на сайте. С помощью QNetworkAccessManager получаем JSON файл и производим его разбор, благодаря классам библиотеки Qt : QJsonDocument, QJsonObject, QJsonArray. В случае с программой EColor на сайте содержится JSON файл с названием программы, полной версией в строковом варианте и тремя объектами с Мажорной частью версии, Минорной и Патч-версией. При разборе файла производится сравнение текущей версии программы с той, которая находится на сайте. В случае, если на сайте выложена более свежая версия, то программа сообщает об этом пользователю.
- 1. Структура проекта для разбора JSON
- 2. JSONParser.pro
- 3. widget.h
- 4. widget.cpp
- 5. Итог
- 6. Видеоурок
В корневом объекте файла располагается три объекта, второй из которых является массивом. Первый объект - это строковое свойство "departament" , которое содержит название отдела. Второй объект - это массив с именами и фамилиями сотрудников. А третий объект - это число сотрудников типа Integer .
Видеоурок
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Работа с моделью DOM является альтернативой десериализации с помощью JsonSerializer :
- Если у вас нет типа для десериализации в.
- Если полученный JSON-код не имеет фиксированной схемы и должен быть проверен для получения сведений о том, что он содержит.
System.Text.Json предоставляет два способа создания модели DOM JSON.
-
классы, производные от него в System.Text.Json.Nodes пространстве имен, предоставляют возможность создания изменяемой модели DOM. Доступ к элементам JSON, составляющим полезные данные, можно получить с JsonNode помощью типов, JsonObjectJsonArray ,, JsonValue и JsonElement . Дополнительные сведения см. в разделе использование JsonNode далее в этой статье.
При выборе между JsonDocument и JsonNode необходимо учитывать следующие факторы.
- JsonNode Модель DOM можно изменить после ее создания. JsonDocument Модель DOM является неизменяемой.
- JsonDocument Модель DOM обеспечивает более быстрый доступ к своим данным.
Настройка экранирования символов
Параметр StringEscapeHandling JsonTextWriter предлагает варианты для экранирования всех символов, не являющихся символами ASCII, или символов HTML. По умолчанию Utf8JsonWriter экранирует все символы, отличные от ASCII, и символы HTML. Такое экранирование выполняется в целях глубокой защиты. Чтобы указать другую политику экранирования, создайте JavaScriptEncoder и задайте JsonWriterOptions.Encoder. Дополнительные сведения см. в статье Настройка кодировки символов.
Use Utf8JsonReader
Utf8JsonReader is a high-performance, low allocation, forward-only reader for UTF-8 encoded JSON text, read from a ReadOnlySpan or ReadOnlySequence . The Utf8JsonReader is a low-level type that can be used to build custom parsers and deserializers. The JsonSerializer.Deserialize method uses Utf8JsonReader under the covers. The Utf8JsonReader can't be used directly from Visual Basic code. For more information, see Visual Basic support.
The following example shows how to use the Utf8JsonReader class:
The preceding code assumes that the jsonUtf8 variable is a byte array that contains valid JSON, encoded as UTF-8.
Write null values
To write null values by using Utf8JsonWriter , call:
-
to write a key-value pair with null as the value. to write null as an element of a JSON array.
For a string property, if the string is null, WriteString and WriteStringValue are equivalent to WriteNull and WriteNullValue .
Read with multi-segment ReadOnlySequence
If your JSON input is a ReadOnlySpan , each JSON element can be accessed from the ValueSpan property on the reader as you go through the read loop. However, if your input is a ReadOnlySequence (which is the result of reading from a PipeReader), some JSON elements might straddle multiple segments of the ReadOnlySequence object. These elements would not be accessible from ValueSpan in a contiguous memory block. Instead, whenever you have a multi-segment ReadOnlySequence as input, poll the HasValueSequence property on the reader to figure out how to access the current JSON element. Here's a recommended pattern:
Свойства
Возвращает общее число байтов, уже использованных этим экземпляром Utf8JsonReader.
Возвращает глубину текущего токена.
Возвращает текущее состояние Utf8JsonReader для передачи в конструктор Utf8JsonReader с дополнительными данными.
Возвращает значение, указывающее, какое свойство Value нужно использовать для получения значения токена.
Возвращает режим данного экземпляра Utf8JsonReader, который указывает, были ли предоставлены все данные JSON или еще поступят дополнительные данные.
Возвращает текущий SequencePosition в рамках предоставленных входных данных ReadOnlySequence в кодировке UTF-8 или значение по умолчанию SequencePosition, если структура Utf8JsonReader была создана с использованием ReadOnlySpan.
Возвращает индекс, с которого начинается последний обработанный токен JSON (в заданном входном тексте UTF-8), пропуская все пробелы.
Возвращает тип последнего обработанного токена JSON в тексте JSON с кодировкой UTF-8.
Получает необработанное значение последнего обработанного токена в виде среза полезных входных данных ReadOnlySequence, только если токен содержится в нескольких сегментах.
Получает необработанное значение последнего обработанного токена в виде среза полезных входных данных ReadOnlySpan, если токен помещается в один сегмент или если модуль чтения был создан с использованием полезных данных JSON, содержащихся в ReadOnlySpan.
Deserialize subsections of a JSON payload
The following example shows how to use JsonNode to navigate to a subsection of a JSON tree and deserialize a single value, a custom type, or an array from that subsection.
Utf8JsonReader is a ref struct
Use Utf8JsonWriter
The following example shows how to use the Utf8JsonWriter class:
Create a JsonNode DOM with object initializers and make changes
The following example shows how to:
- Create a DOM by using object initializers.
- Make changes to a DOM.
Read UTF-8 text
To achieve the best possible performance while using the Utf8JsonReader , read JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. For a code example, see Filter data using Utf8JsonReader.
JsonNode с JsonSerializerOptions
Можно использовать JsonSerializer для сериализации и десериализации экземпляра JsonNode . Однако при использовании перегрузки, которая принимает JsonSerializerOptions , экземпляр Options используется только для получения пользовательских преобразователей. Другие функции экземпляра Options не используются. Например, если задать для значение JsonSerializerOptions.DefaultIgnoreCondition и вызвать JsonSerializer перегрузку, принимающую JsonSerializerOptions , свойства со значением NULL не будут WhenWritingNull учитываться.
Те же ограничения применяются к JsonNode методам, принимающим JsonSerializerOptions параметр: WriteTo(Utf8JsonWriter, JsonSerializerOptions) и ToJsonString(JsonSerializerOptions) . Эти API-интерфейсы используют JsonSerializerOptions только для получения пользовательских преобразователей.
В следующем примере показан результат использования методов, которые принимают JsonSerializerOptions параметр и сериализуются JsonNode экземпляр:
Если требуются функции JsonSerializerOptions , отличные от пользовательских преобразователей, используйте JsonSerializer со строго типизированными целевыми объектами (например, Person классом в этом примере), а не JsonNode .
Используйте Utf8JsonReader .
Utf8JsonReader — это последовательный модуль чтения текста JSON в кодировке UTF-8 из ReadOnlySpan или ReadOnlySequence с высокой производительностью и низким уровнем распределения. Utf8JsonReader — это низкоуровневый тип, с помощью которого можно создавать пользовательские средства синтаксического анализа и десериализаторы. Метод JsonSerializer.Deserialize использует Utf8JsonReader , как описано выше. Utf8JsonReader не может использоваться непосредственно из кода Visual Basic. дополнительные сведения см. в разделе поддержка Visual Basic.
В следующем примере показано, как использовать класс Utf8JsonReader.
В приведенном выше коде предполагается, что переменной jsonUtf8 является массив байтов, который содержит допустимые данные JSON в кодировке UTF-8.
Write with UTF-8 text
To achieve the best possible performance while using the Utf8JsonWriter , write JSON payloads already encoded as UTF-8 text rather than as UTF-16 strings. Use JsonEncodedText to cache and pre-encode known string property names and values as statics, and pass those to the writer, rather than using UTF-16 string literals. This is faster than caching and using UTF-8 byte arrays.
This approach also works if you need to do custom escaping. System.Text.Json doesn't let you disable escaping while writing a string. However, you could pass in your own custom JavaScriptEncoder as an option to the writer, or create your own JsonEncodedText that uses your JavascriptEncoder to do the escaping, and then write the JsonEncodedText instead of the string. For more information, see Customize character encoding.
Запись значений NULL
Чтобы записать значения NULL с помощью Utf8JsonWriter , вызовите:
-
для записи пары "ключ-значение" со значением NULL. для записи значения NULL в качестве элемента массива JSON.
Для строкового свойства, если строка имеет значение NULL, WriteString и WriteStringValue эквивалентны WriteNull и WriteNullValue .
Используйте Utf8JsonWriter .
В следующем примере показано, как использовать класс Utf8JsonWriter.
Поиск вложенных элементов в JsonDocument и JsonElement
JsonElement Для поиска требуется последовательный поиск по свойствам, поэтому они относительно медленные (например, при использовании TryGetProperty ). System.Text.Json предназначен для сокращения времени начального анализа, а не времени поиска. Поэтому рекомендуется использовать следующие подходы для оптимизации производительности при поиске по объекту JsonDocument :
- Используйте встроенные перечислители (EnumerateArray и EnumerateObject) вместо создания собственных индексов или циклов.
- Не выполняйте последовательный поиск по всему JsonDocument в каждом свойстве с помощью RootElement . Вместо этого выполните поиск по вложенным объектам JSON на основе известной структуры данных JSON. Например, приведенные выше примеры кода ищут Grade свойство в Student объектах путем прохода Student по объектам и получения значения для каждого из Grade них, а не для поиска по всем JsonElement объектам, которые ищут Grade Свойства. Выполнение второго из них приведет к ненужным проходам по тем же данным.
Filter data using Utf8JsonReader
The following example shows how to synchronously read a file, and search for a value.
The preceding code:
Assumes the JSON contains an array of objects and each object may contain a "name" property of type string.
Counts objects and "name" property values that end with "University".
Assumes the file is encoded as UTF-16 and transcodes it into UTF-8. A file encoded as UTF-8 can be read directly into a ReadOnlySpan , by using the following code:
If the file contains a UTF-8 byte order mark (BOM), remove it before passing the bytes to the Utf8JsonReader , since the reader expects text. Otherwise, the BOM is considered invalid JSON, and the reader throws an exception.
Here's a JSON sample that the preceding code can read. The resulting summary message is "2 out of 4 have names that end with 'University'":
Структура проекта для разбора JSON
- JSONParser.pro - профайл проекта;
- main.cpp - основной файл исходных кодов проекта;
- widget.h - заголовочный файл окна приложения, в котором содержится поле QTextEdit, в которое будет помещен результат парсинга файла;
- widget.cpp - файл исходных кодов с QNetworkAccessManager.
- widget.ui - файл интерфейса программы.
Write raw JSON
In some scenarios, you might want to write "raw" JSON to a JSON payload that you're creating with Utf8JsonWriter . You can use Utf8JsonWriter.WriteRawValue to do that. Here are typical scenarios:
You have an existing JSON payload that you want to enclose in new JSON.
You want to format values differently from the default Utf8JsonWriter formatting.
For example, you might want to customize number formatting. By default, System.Text.Json omits the decimal point for whole numbers, writing 1 rather than 1.0 , for example. The rationale is that writing fewer bytes is good for performance. But suppose the consumer of your JSON treats numbers with decimals as doubles, and numbers without decimals as integers. You might want to ensure that the numbers in an array are all recognized as doubles, by writing a decimal point and zero for whole numbers. The following example shows how to do that:
Чтение текста UTF-8
Для достижения наилучшей производительности при использовании Utf8JsonReader читайте полезные данные JSON, уже закодированные как текст UTF-8, а не как строки UTF-16. Пример кода см. в разделе Фильтрация данных с помощью Utf8JsonReader.
Пример среднего уровня Жсонноде
В следующем примере выбирается массив JSON, содержащий целочисленные значения, и вычисляется среднее значение:
- Вычисляет среднее значение для объектов в массиве Students , имеющих свойство Grade .
- Назначает значение по умолчанию 70 для учащихся, у которых нет оценки.
- Возвращает число учащихся от Count свойства JsonArray .
widget.h
Подключаем класс QNetworkAccessManager , также в заголовочном файле объявлен СЛОТ onResult(QNetworkReply *reply) , в котором будет разбираться JSON файл при получении ответа от сайта с содержимым файла.
Комментарии
Utf8JsonReader обрабатывает текст последовательно без кэширования и по умолчанию строго соответствует JSON RFC.
При Utf8JsonReader обнаружении недопустимого JSON возникает JsonException ошибка с основными сведениями об ошибке, такими как номер строки и позиция байтов в строке.
Так как этот тип является структурой ссылок, она не поддерживает асинхронную структуру напрямую. Однако она обеспечивает поддержку повторного входа для чтения неполных данных и продолжения чтения еще раз.
Чтобы задать максимальную глубину при чтении или разрешить пропуск комментариев, создайте экземпляр JsonReaderOptions и передайте его средству чтения.
Use JsonDocument to write JSON
The following example shows how to write JSON from a JsonDocument:
The preceding code:
- Reads a JSON file, loads the data into a JsonDocument , and writes formatted (pretty-printed) JSON to a file.
- Uses JsonDocumentOptions to specify that comments in the input JSON are allowed but ignored.
- When finished, calls Flush on the writer. An alternative is to let the writer auto-flush when it's disposed.
Here's an example of JSON input to be processed by the example code:
The result is the following pretty-printed JSON output:
Использовать JsonDocument для записи JSON
В следующем примере показано, как записать JSON код из JsonDocument.
- Считывает JSON-файл, загружает данные в JsonDocument и записывает форматированный (структурированный) код JSON в файл.
- Использует JsonDocumentOptions, чтобы указать, что комментарии во входных данных JSON разрешены, но пропускаются.
- По завершении для модуля записи вызывается Flush. В качестве альтернативы можно разрешить автоматическую запись в модуле записи при его удалении.
Ниже приведен пример входных данных JSON для обработки в примере кода:
В результате получаются следующие структурированные выходные данные JSON:
Используйте JsonDocument .
В следующем примере показано, как использовать класс JsonDocument для произвольного доступа к данным в строке JSON:
- Предполагается, что анализируемый код JSON находится в строке jsonString .
- Вычисляет среднее значение для объектов в массиве Students , имеющих свойство Grade .
- Назначает значение по умолчанию 70 для учащихся, у которых нет оценки.
- JsonDocument Создает экземпляр в операторе, using поскольку JsonDocument реализует IDisposable . JsonDocument После удаления экземпляра вы также теряете доступ ко всем его JsonElement экземплярам. Чтобы хранить доступ к JsonElement экземпляру, создайте его копию перед ликвидацией родительского JsonDocument экземпляра. Чтобы создать копию, вызовите JsonElement.Clone . Дополнительные сведения см. в разделе жсондокумент — IDisposable.
В приведенном выше примере кода количество учащихся увеличивается путем увеличения count переменной с каждой итерацией. Альтернативой является вызов GetArrayLength, как показано в следующем примере:
Ниже приведен пример JSON, обрабатываемый этим кодом:
Аналогичный пример, в котором используется JsonNode вместо JsonDocument , см. в разделе Пример среднего уровня жсонноде.
JsonDocument является IDisposable
JsonDocument создает выполняющееся в памяти представление данных в едином буфере. JsonDocument Поэтому тип реализует IDisposable и должен использоваться внутри using блока.
Возвращайте JsonDocument из API только в том случае, если хотите передать владение временем существования и ответственность вызывающему объекту. В большинстве случаев это необязательно. Если вызывающему объекту необходимо работать со всем документом JSON, возвращайте CloneRootElement, то есть JsonElement. Если вызывающему объекту необходимо работать с определенным элементом в документе JSON, возвращайте Clone этого JsonElement. Если вы возвращаете RootElement или вложенный элемент напрямую, не выполняя Clone , вызывающий объект не сможет получить доступ к возвращаемому объекту JsonElement после того, как JsonDocument , которому он принадлежит, будет удален.
Ниже приведен пример, в котором необходимо сделать Clone .
Приведенный выше код ждет JsonElement , содержащий свойство fileName . Он открывает JSON-файл и создает JsonDocument . Метод предполагает, что вызывающий объект хочет работать со всем документом, поэтому он возвращает Clone RootElement .
Если вы получаете JsonElement и возвращаете вложенный элемент, нет необходимости возвращать Clone вложенного элемента. Вызывающий объект отвечает за поддержание активности JsonDocument , которому принадлежит переданный JsonElement . Пример:
JsonNode average grade example
The following example selects a JSON array that has integer values and calculates an average value:
The preceding code:
- Calculates an average grade for objects in a Students array that have a Grade property.
- Assigns a default grade of 70 for students who don't have a grade.
- Gets the number of students from the Count property of JsonArray .
Конструкторы
Инициализирует новый экземпляр структуры Utf8JsonReader, который обрабатывает последовательность текста в кодировке UTF-8, доступную только для чтения, и указывает, содержат ли входные данные весь текст для обработки.
Инициализирует новый экземпляр структуры Utf8JsonReader, который обрабатывает последовательность текста в кодировке UTF-8, доступную только для чтения, с использованием указанных параметров.
Инициализирует новый экземпляр структуры Utf8JsonReader, который обрабатывает доступный только для чтения диапазон текста в кодировке UTF-8 и указывает, содержат ли входные данные весь текст для обработки.
Инициализирует новый экземпляр структуры Utf8JsonReader, который обрабатывает диапазон текста в кодировке UTF-8, доступный только для чтения, с использованием указанных параметров.
Customize character escaping
The StringEscapeHandling setting of JsonTextWriter offers options to escape all non-ASCII characters or HTML characters. By default, Utf8JsonWriter escapes all non-ASCII and HTML characters. This escaping is done for defense-in-depth security reasons. To specify a different escaping policy, create a JavaScriptEncoder and set JsonWriterOptions.Encoder. For more information, see Customize character encoding.
Utf8JsonReader является структурой ссылок
Read null values into nullable value types
The built-in System.Text.Json APIs return only non-nullable value types. For example, Utf8JsonReader.GetBoolean returns a bool . It throws an exception if it finds Null in the JSON. The following examples show two ways to handle nulls, one by returning a nullable value type and one by returning the default value:
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Предоставляет высокопроизводительный API для однонаправленного доступа только для чтения к тексту JSON в кодировке UTF-8.
widget.cpp
Процесс заключается в том, чтобы создать объект QJsonDocument и записать в него содержимое ответа QNetworkReply. После чего забираем из документа корневой объект root , который будет содержать все три свойства. После этого забираем по названиям свойств их значения. Из второго свойства "employes" забираем массив с именами и фамилиями сотрудников отдела. Все данные помещаем в поле ui->textEdit.
В результате работы данного программного кода получится следующий результат, который показан на ниже следующем изображении. Также работу приложения Вы можете увидеть на в видеоуроке.
JsonNode with JsonSerializerOptions
You can use JsonSerializer to serialize and deserialize an instance of JsonNode . However, if you use an overload that takes JsonSerializerOptions , the options instance is only used to get custom converters. Other features of the options instance are not used. For example, if you set JsonSerializerOptions.DefaultIgnoreCondition to WhenWritingNull and call JsonSerializer with an overload that takes JsonSerializerOptions , null properties won't be ignored.
The same limitation applies to the JsonNode methods that take a JsonSerializerOptions parameter: WriteTo(Utf8JsonWriter, JsonSerializerOptions) and ToJsonString(JsonSerializerOptions). These APIs use JsonSerializerOptions only to get custom converters.
The following example illustrates the result of using methods that take a JsonSerializerOptions parameter and serialize a JsonNode instance:
If you need features of JsonSerializerOptions other than custom converters, use JsonSerializer with strongly typed targets (such as the Person class in this example) rather than JsonNode .
Use ValueTextEquals for property name lookups
Don't use ValueSpan to do byte-by-byte comparisons by calling SequenceEqual for property name lookups. Call ValueTextEquals instead, because that method unescapes any characters that are escaped in the JSON. Here's an example that shows how to search for a property that is named "name":
Use JsonDocument
The following example shows how to use the JsonDocument class for random access to data in a JSON string:
The preceding code:
- Assumes the JSON to analyze is in a string named jsonString .
- Calculates an average grade for objects in a Students array that have a Grade property.
- Assigns a default grade of 70 for students who don't have a grade.
- Creates the JsonDocument instance in a using statement because JsonDocument implements IDisposable . After a JsonDocument instance is disposed, you lose access to all of its JsonElement instances also. To retain access to a JsonElement instance, make a copy of it before the parent JsonDocument instance is disposed. To make a copy, call JsonElement.Clone. For more information, see JsonDocument is IDisposable.
The preceding example code counts students by incrementing a count variable with each iteration. An alternative is to call GetArrayLength, as shown in the following example:
Here's an example of the JSON that this code processes:
For a similar example that uses JsonNode instead of JsonDocument , see JsonNode average grade example.
Использование ValueTextEquals для поиска имени свойства
Не используйте ValueSpan для побайтового сравнения путем вызова SequenceEqual для поиска имени свойства. Вместо этого вызовите ValueTextEquals, так как этот метод отменяет экранирование всех символов, которые экранированы в JSON. Ниже приведен пример, демонстрирующий поиск свойства с именем name:
Запись значений TimeSpan, URI или char
Чтобы записать Timespan значения, Uri или char , отформатируйте их как строки (вызвав ToString() , например) и вызовите WriteStringValue .
Use JsonNode
The following example shows how to use JsonNode and the other types in the System.Text.Json.Nodes namespace to:
- Create a DOM from a JSON string
- Write JSON from a DOM.
- Get a value, object, or array from a DOM.
Используйте JsonNode .
В следующем примере показано, как использовать JsonNode и другие типы в System.Text.Json.Nodes пространстве имен для:
- Создание модели DOM на основе строки JSON
- Запись JSON из модели DOM.
- Получение значения, объекта или массива из модели DOM.
Создание модели DOM Жсонноде с инициализаторами объектов и внесение изменений
В приведенном ниже примере показано, как выполнить следующие задачи.
- Создание модели DOM с помощью инициализаторов объектов.
- Внесение изменений в модель DOM.
Чтение из потока с помощью Utf8JsonReader
При чтении большого файла (размером гигабайт и более) вы, скорее всего, предпочтете не загружать весь файл в память сразу. В таких ситуациях можно использовать FileStream.
При использовании Utf8JsonReader для чтения из потока данных действуют следующие правила:
- Буфер, который накапливает часть данных в формате JSON, должен быть не меньше самого крупного из возможных маркеров JSON, чтобы средство чтения могло продвигаться вперед.
- Размер буфера должен быть не меньше самой большой последовательности пробелов в JSON.
- Средство чтения не запоминает прочитанные данные, пока не дойдет до следующего свойства TokenType в структуре JSON. Таким образом, если в буфере еще остались байты, их нужно снова передать в средство чтения. Для определения количества оставшихся байтов можно использовать BytesConsumed.
В примере кода ниже показано, как выполнять чтение из потока. Этот пример демонстрирует MemoryStream. Аналогичный код будет работать и с FileStream, за исключением случаев, когда в начале FileStream содержится метка порядка байтов UTF-8. В этом случае необходимо удалить эти три байта из буфера, прежде чем передавать оставшиеся байты в Utf8JsonReader . В противном случае средство чтения создаст исключение, поскольку метка порядка байтов не считается допустимой частью JSON.
Пример кода начинает работу с буфером в 4 КБ и удваивает размер буфера каждый раз, когда тот оказывается недостаточно велик для размещения полного маркера JSON, который потребуется средству чтения для дальнейшего перемещения по структуре данных JSON. Представленный в этом примере фрагмент JSON приводит к увеличению размера буфера только в том случае, если задан очень маленький начальный размер буфера, например 10 байт. Если указать для буфера начальное значение 10, то инструкции Console.WriteLine продемонстрируют причину и последствия увеличения размера буфера. При начальном размере буфера 4 КБ весь пример JSON целиком отображается в каждой Console.WriteLine , и размер буфера увеличивать не нужно.
В примере выше ограничение на увеличение размера буфера не установлено. Если размер маркера будет слишком большой, такой код может возвратить ошибку с исключением OutOfMemoryException. Такое может произойти, если в JSON есть маркер размером около 1 ГБ, поскольку удвоение размера 1 ГБ приводит к переполнению буфера int32 .
Фильтрация данных с помощью Utf8JsonReader
В следующем примере показано, как синхронно выполнить чтение файла и поиск значения.
Предполагается, что JSON содержит массив объектов и каждый объект может содержать свойство name строкового типа.
Подсчитывает объекты и значения свойств name, заканчивающиеся на University.
Предполагается, что файл кодируется как UTF-16 и перекодируется в UTF-8. Файл, закодированный как UTF-8, можно прочитать непосредственно в ReadOnlySpan с помощью следующего кода:
Если файл содержит метку порядка байтов (BOM) UTF-8, удалите ее перед передачей байтов в Utf8JsonReader , так как средство чтения ждет текст. В противном случае метка порядка байтов считается недопустимым кодом JSON, и средство чтения создает исключение.
JSONParser.pro
Не забываем подключить в профайле проекта модуль network , чтобы была возможность работать с классом QNetworkAccessManager.
Десериализация подразделов полезных данных JSON
В следующем примере показано, как использовать жсонноде для перехода к подразделу дерева JSON и десериализации одного значения, пользовательского типа или массива из этого подраздела.
Чтение с помощью ReadOnlySequence с несколькими сегментами
Если входные данные JSON являются реадонлиспан , к каждому элементу JSON можно получить доступ из ValueSpan свойства в модуле чтения, когда вы просматриваете цикл чтения. Однако если входные данные представляют собой реадонлисекуенце (что является результатом чтения из), некоторые элементы JSON могут повлечь за собой PipeReader несколько сегментов ReadOnlySequence объекта. Эти элементы не будут доступны из ValueSpan в непрерывном блоке памяти. Вместо этого каждый раз, когда у вас есть ReadOnlySequence с несколькими сегментами в качестве входных данных, следует опросить свойство HasValueSequence в модуле чтения, чтобы выяснить, как получить доступ к текущему элементу JSON. Вот рекомендуемый шаблон:
JsonDocument с JsonSerializerOptions
Можно использовать JsonSerializer для сериализации и десериализации экземпляра JsonDocument . Однако реализация для чтения и записи JsonDocument экземпляров с помощью JsonSerializer — это оболочка JsonDocument.ParseValue(Utf8JsonReader) для и JsonDocument.WriteTo(Utf8JsonWriter) . Эта оболочка не пересылает никакие JsonSerializerOptions (функции сериализатора) в Utf8JsonReader или Utf8JsonWriter . Например, если задать для значение JsonSerializerOptions.DefaultIgnoreCondition и вызвать JsonSerializer перегрузку, принимающую JsonSerializerOptions , свойства со значением NULL не будут WhenWritingNull учитываться.
В следующем примере показан результат использования методов, которые принимают JsonSerializerOptions параметр и сериализуются JsonDocument экземпляр:
Если требуются функции JsonSerializerOptions , используйте JsonSerializer со строго типизированными целевыми объектами (например, Person классом в этом примере), а не JsonDocument .
Запись с помощью текста UTF-8
Для достижения наилучшей производительности при использовании Utf8JsonWriter записывайте полезные данные JSON, уже закодированные как текст UTF-8, а не как строки UTF-16. Используйте JsonEncodedText, чтобы кэшировать и предварительно закодировать известные имена и значения свойств строки как статические, а затем передать их в модуль записи вместо использования строковых литералов UTF-16. Это быстрее, чем кэширование и использование байтовых массивов UTF-8.
Этот подход также работает, если необходимо выполнить пользовательское экранирование. System.Text.Json не позволяет отключить экранирование при записи строки. Однако можно передать собственный пользовательский JavaScriptEncoder в качестве параметра для модуля записи или создать собственный JsonEncodedText , который использует JavascriptEncoder для выполнения экранирования, а затем написать JsonEncodedText вместо строки. Дополнительные сведения см. в статье Настройка кодировки символов.
Read from a stream using Utf8JsonReader
When reading a large file (a gigabyte or more in size, for example), you might want to avoid having to load the entire file into memory at once. For this scenario, you can use a FileStream.
When using the Utf8JsonReader to read from a stream, the following rules apply:
- The buffer containing the partial JSON payload must be at least as large as the largest JSON token within it so that the reader can make forward progress.
- The buffer must be at least as large as the largest sequence of white space within the JSON.
- The reader doesn't keep track of the data it has read until it completely reads the next TokenType in the JSON payload. So when there are bytes left over in the buffer, you have to pass them to the reader again. You can use BytesConsumed to determine how many bytes are left over.
The following code illustrates how to read from a stream. The example shows a MemoryStream. Similar code will work with a FileStream, except when the FileStream contains a UTF-8 BOM at the start. In that case, you need to strip those three bytes from the buffer before passing the remaining bytes to the Utf8JsonReader . Otherwise the reader would throw an exception, since the BOM is not considered a valid part of the JSON.
The sample code starts with a 4KB buffer and doubles the buffer size each time it finds that the size is not large enough to fit a complete JSON token, which is required for the reader to make forward progress on the JSON payload. The JSON sample provided in the snippet triggers a buffer size increase only if you set a very small initial buffer size, for example, 10 bytes. If you set the initial buffer size to 10, the Console.WriteLine statements illustrate the cause and effect of buffer size increases. At the 4KB initial buffer size, the entire sample JSON is shown by each Console.WriteLine , and the buffer size never has to be increased.
The preceding example sets no limit to how large the buffer can grow. If the token size is too large, the code could fail with an OutOfMemoryException exception. This can happen if the JSON contains a token that is around 1 GB or more in size, because doubling the 1 GB size results in a size that is too large to fit into an int32 buffer.
8 Answers 8
Yes you can create a nested data structure people which can be indexed by Anna and Ben . However, you can't index it directly by age and profession (I will get to this part in the code).
The data type of people is of type Json::Value (which is defined in jsoncpp). You are right, it is similar to the nested map, but Value is a data structure which is defined such that multiple types can be stored and accessed. It is similar to a map with a string as the key and Json::Value as the value. It could also be a map between an unsigned int as key and Json::Value as the value (In case of json arrays).
As you can see, you can index the json object only based on the hierarchy of the input data.
Thanks! I understand the idea now. However, it's not quite working yet: If I only add json-forwards.h , json.h and jsoncpp.cpp to the project I get an error message "Invalid operands to binary expression('std::ifstream and 'Json::Value'" at the line people_file >> people. If I do add all the files in include/ I get an error message "Error from reader: * Line 1, Column 1 Syntax error: value, object or array expected." Header search paths are set to both 'include/' and 'dist/'.
Have a look at nlohmann's JSON Repository on GitHub. I have found that it is the most convenient way to work with JSON.
It is designed to behave just like an STL container, which makes its usage very intuitive.
Essentially javascript and C++ work on two different principles. Javascript creates an "associative array" or hash table, which matches a string key, which is the field name, to a value. C++ lays out structures in memory, so the first 4 bytes are an integer, which is an age, then maybe we have a fixed-wth 32 byte string which represents the "profession".
So javascript will handle things like "age" being 18 in one record and "nineteen" in another. C++ can't. (However C++ is much faster).
So if we want to handle JSON in C++, we have to build the associative array from the ground up. Then we have to tag the values with their types. Is it an integer, a real value (probably return as "double"), boolean, a string? It follows that a JSON C++ class is quite a large chunk of code. Effectively what we are doing is implementing a bit of the javascript engine in C++. We then pass our JSON parser the JSON as a string, and it tokenises it, and gives us functions to query the JSON from C++.
JsonDocument with JsonSerializerOptions
You can use JsonSerializer to serialize and deserialize an instance of JsonDocument . However, the implementation for reading and writing JsonDocument instances by using JsonSerializer is a wrapper over the JsonDocument.ParseValue(Utf8JsonReader) and JsonDocument.WriteTo(Utf8JsonWriter). This wrapper does not forward any JsonSerializerOptions (serializer features) to Utf8JsonReader or Utf8JsonWriter . For example, if you set JsonSerializerOptions.DefaultIgnoreCondition to WhenWritingNull and call JsonSerializer with an overload that takes JsonSerializerOptions , null properties won't be ignored.
The following example illustrates the result of using methods that take a JsonSerializerOptions parameter and serialize a JsonDocument instance:
If you need features of JsonSerializerOptions , use JsonSerializer with strongly typed targets (such as the Person class in this example) rather than JsonDocument .
Write Timespan, Uri, or char values
To write Timespan , Uri , or char values, format them as strings (by calling ToString() , for example) and call WriteStringValue.
Считывание значений NULL в типы значений, допускающие значения NULL
Встроенные API System.Text.Json возвращают только типы значений, не допускающие значения NULL. Например, Utf8JsonReader.GetBoolean возвращает bool . Он вызывает исключение, если обнаруживает Null в JSON. В следующих примерах показаны два способа обработки значений NULL: возврат типа значения, допускающего значение NULL, и возврат значения по умолчанию:
Working with a DOM is an alternative to deserialization with JsonSerializer:
- When you don't have a type to deserialize into.
- When the JSON you receive doesn't have a fixed schema and must be inspected to know what it contains.
System.Text.Json provides two ways to build a JSON DOM:
-
and the classes that derive from it in the System.Text.Json.Nodes namespace provide the ability to create a mutable DOM. The JSON elements that compose the payload can be accessed via the JsonNode, JsonObject, JsonArray, JsonValue, and JsonElement types. For more information, see Use JsonNode later in this article.
Consider the following factors when choosing between JsonDocument and JsonNode :
- The JsonNode DOM can be changed after it's created. The JsonDocument DOM is immutable.
- The JsonDocument DOM provides faster access to its data.
JsonDocument is IDisposable
JsonDocument builds an in-memory view of the data into a pooled buffer. Therefore the JsonDocument type implements IDisposable and needs to be used inside a using block.
Only return a JsonDocument from your API if you want to transfer lifetime ownership and dispose responsibility to the caller. In most scenarios, that isn't necessary. If the caller needs to work with the entire JSON document, return the Clone of the RootElement, which is a JsonElement. If the caller needs to work with a particular element within the JSON document, return the Clone of that JsonElement. If you return the RootElement or a sub-element directly without making a Clone , the caller won't be able to access the returned JsonElement after the JsonDocument that owns it is disposed.
Here's an example that requires you to make a Clone :
The preceding code expects a JsonElement that contains a fileName property. It opens the JSON file and creates a JsonDocument . The method assumes that the caller wants to work with the entire document, so it returns the Clone of the RootElement .
If you receive a JsonElement and are returning a sub-element, it's not necessary to return a Clone of the sub-element. The caller is responsible for keeping alive the JsonDocument that the passed-in JsonElement belongs to. For example:
How to search a JsonDocument and JsonElement for sub-elements
Searches on JsonElement require a sequential search of the properties and hence are relatively slow (for example when using TryGetProperty ). System.Text.Json is designed to minimize initial parse time rather than lookup time. Therefore, use the following approaches to optimize performance when searching through a JsonDocument object:
- Use the built-in enumerators (EnumerateArray and EnumerateObject) rather than doing your own indexing or loops.
- Don't do a sequential search on the whole JsonDocument through every property by using RootElement . Instead, search on nested JSON objects based on the known structure of the JSON data. For example, the preceding code examples look for a Grade property in Student objects by looping through the Student objects and getting the value of Grade for each, rather than searching through all JsonElement objects looking for Grade properties. Doing the latter would result in unnecessary passes over the same data.
Методы
Считывает следующее значение токена JSON из источника в виде Boolean.
Анализирует текущее значение токена JSON из источника в виде Byte.
Анализирует текущее значение токена JSON из источника и декодирует строку JSON в кодировке Base64 в виде массива байтов.
Анализирует текущее значение токена JSON из источника как комментарий, перекодируя его как String.
Считывает следующее значение токена JSON из источника и преобразует его в DateTime.
Считывает следующее значение токена JSON из источника и преобразует его в DateTimeOffset.
Считывает следующее значение токена JSON из источника и преобразует его в Decimal.
Считывает следующее значение токена JSON из источника и преобразует его в Double.
Считывает следующее значение токена JSON из источника и преобразует его в Guid.
Анализирует текущее значение токена JSON из источника в виде Int16.
Считывает следующее значение токена JSON из источника и преобразует его в Int32.
Считывает следующее значение токена JSON из источника и преобразует его в Int64.
Анализирует текущее значение токена JSON из источника в виде SByte.
Считывает следующее значение токена JSON из источника и преобразует его в Single.
Считывает следующее значение токена JSON из источника неэкранированным и перекодированным в строку.
Анализирует текущее значение токена JSON из источника в виде UInt16.
Считывает следующее значение токена JSON из источника и преобразует его в UInt32.
Считывает следующее значение токена JSON из источника и преобразует его в UInt64.
Считывает следующий токен JSON из источника входных данных.
Пропускает дочерний узел текущего токена JSON.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Byte и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника, декодирует строку JSON в кодировке Base64 в виде массива байтов и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как DateTime и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как DateTimeOffset и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Decimal и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Double и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Guid и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Int16 и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Int32 и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Int64 и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как SByte и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как Single и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как UInt16 и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как UInt32 и возвращает значение, указывающее, завершилась ли операция.
Пытается выполнить синтаксический анализ текущего значения токена JSON из источника как UInt64 и возвращает значение, указывающее, завершилась ли операция.
Пытается пропустить дочерние узлы текущего токена JSON.
Сравнивает текст в кодировке UTF-8 в диапазоне байтов только для чтения с неэкранированным значением токена JSON в источнике и возвращает значение, указывающее, совпадают ли они.
Сравнивает текст в диапазоне символов только для чтения с неэкранированным значением токена JSON в источнике и возвращает значение, указывающее, совпадают ли они.
Сравнивает текст строки с неэкранированным значением токена JSON в источнике и возвращает значение, указывающее, совпадают ли они.
I'm trying to read in a JSON file. So far I have focused on using the jsoncpp library. However, the documentation is quite hard to understand for me. Could anyone explain in lay terms what it does?
Say I have a people.json which looks like this:
What happens when I read this in? Can I create some sort of data structure people which I can index by Anna and Ben as well as age and profession ? What would be the data type of people ? I thought it would be something similar to a (nested) map, but map values always have to have the same type, don't they?
I have worked with python before and my "goal" (which may be ill-set for C++) is to obtain the equivalent of a nested python dictionary.
Please note that JSON (contrary to JavaScript) requires that keys are enclosed in double quotation marks.
I know this has been suggested down below, but to anyone who is reading this now, seriously consider nlohmann::json if you are writing in C++.
Запись необработанного JSON
В некоторых сценариях может потребоваться записать "необработанный" JSON в полезные данные JSON, которые создаются с помощью Utf8JsonWriter . Для этого можно использовать Utf8JsonWriter.WriteRawValue . Ниже приведены типичные сценарии.
У вас есть существующие полезные данные JSON, которые необходимо заключить в новый JSON.
Необходимо отформатировать значения иначе, чем при форматировании по умолчанию Utf8JsonWriter .
Например, может потребоваться настроить форматирование чисел. По умолчанию System.Text.Json опускает десятичную запятую для целых чисел, 1 а не 1.0 , например. Смысл состоит в том, что запись меньшего количества байтов хорошо подходит для повышения производительности. Но предположим, что потребитель JSON рассматривает числа с десятичными знаками в виде чисел типа Double, а числа без десятичных чисел — как целые числа. Может потребоваться, чтобы числа в массиве распознавались как Double, путем записи десятичной запятой и нуля для целых чисел. Следующий пример показывает, как это сделать:
Читайте также: