При работе с внешними системами обмена данными программисты 1С часто сталкиваются с файлами JSON огромного объема (сотни мегабайт или даже несколько гигабайт). Основная проблема заключается в том, что стандартный объектный метод чтения ПрочитатьJSON() при загрузке всего файла целиком пытается поместить все данные в оперативную память. Если файл велик, это неизбежно приводит к ошибке "Недостаточно памяти" или критическому замедлению работы сервера.
С другой стороны, чисто потоковое чтение (через объект ЧтениеJSON и обход в цикле) крайне трудозатратно в разработке: программисту приходится вручную обрабатывать каждое событие начала объекта, чтения свойства и окончания массива. В этой статье мы подробно разберем, как найти "золотую середину" и использовать гибридный подход.
Рассмотрим стандартную ситуацию: мы получаем файл, который представляет собой огромный массив объектов (например, выгрузка товаров или остатков). Структура файла выглядит примерно так:
[
{
"ID": "00001",
"Наименование": "Товар 1",
"Цены": [ {"Тип": "Оптовая", "Цена": 100}, {"Тип": "Розничная", "Цена": 120} ],
"Остатки": [ {"Склад": "Основной", "Количество": 10} ]
},
{
"ID": "00002",
"Наименование": "Товар 2",
...
}
]
Если мы будем читать это потоком, нам придется писать десятки строк кода, чтобы "поймать" начало массива "Цены", затем в цикле читать каждый объект цены, проверять свойства и так далее. Это сложно отлаживать и поддерживать. Мы хотим читать глобальный массив потоково (по одному товару за раз), а внутреннюю структуру товара (свойства, вложенные массивы) получать сразу в виде удобной Структуры или Соответствия 1С.
Решение существует в самой платформе 1С:Предприятие 8.3, хотя оно не всегда очевидно из документации. Основной секрет заключается в том, что функция ПрочитатьJSON() может принимать в качестве источника данных не только ЧтениеТекста, но и уже инициализированный объект ЧтениеJSON, который находится в процессе работы.
Проанализируем алгоритм работы этого метода:
ПрочитатьJSON(ЧтениеJSON) вычитывает ровно один текущий объект целиком, превращает его в структуру 1С и останавливается.Рассмотрим практический пример кода, который реализует эту логику. Представим, что нам нужно обработать файл с товарами, не загружая его целиком в память.
// Инициализируем чтение файла
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл("C:\Exchange\HugeData.json");
// Читаем начало глобального массива [
ЧтениеJSON.Прочитать();
// Основной цикл потокового обхода
Пока ЧтениеJSON.Прочитать() Цикл
// Проверяем, начался ли новый объект товара {
Если ЧтениеJSON.ТипТекущегоЗначения = ТипТекущегоЗначенияJSON.НачалоОбъекта Тогда
// ВАЖНЫЙ МОМЕНТ:
// Мы вызываем объектное чтение для ОДНОГО элемента массива.
// Платформа сама прочитает всё содержимое объекта до закрывающей скобки }
// и вернет нам готовую структуру.
ДанныеОбъекта = ПрочитатьJSON(ЧтениеJSON);
// Теперь мы работаем с ДанныеОбъекта как с обычной структурой 1С
ОбработатьДанныеТовара(ДанныеОбъекта);
// После вызова ПрочитатьJSON, указатель ЧтениеJSON уже стоит
// на событии КонецОбъекта. Следующая итерация цикла .Прочитать()
// переведет нас к следующему элементу массива.
КонецЕсли;
КонецЦикла;
ЧтениеJSON.Закрыть();
Проанализируем ситуацию с точки зрения потребления ресурсов. При таком подходе в оперативной памяти одновременно находится:
ЧтениеJSON.Сколько бы миллионов товаров ни было в файле, потребление памяти будет стабильным и низким, ограниченным лишь размером самого крупного одиночного объекта в массиве. Это позволяет обрабатывать файлы размером в несколько гигабайт даже на серверах с ограниченными ресурсами.
В Сообщении 8 форума поднимался вопрос: а что делать, если в JSON записаны данные, которые должны стать ссылками 1С (справочники, документы)?
При использовании гибридного метода мы можем задействовать второй параметр функции ПрочитатьJSON() — ФункцияВосстановленияДанных. Это позволяет нам на лету превращать строковые ГУИДы или коды в реальные ссылки 1С прямо в момент "захвата" объекта из потока.
Разберем, как это реализовать:
Функция ВосстановлениеДанных(Свойство, Значение, ДополнительныеПараметры) Экспорт
Если Свойство = "ТоварСсылка" Тогда
Возврат Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Значение));
КонецЕсли;
Возврат Значение;
КонецФункции
// В основном коде при вызове:
ДанныеОбъекта = ПрочитатьJSON(ЧтениеJSON, , "ВосстановлениеДанных", ЭтотОбъект);
Такой подход делает код чистым: логика преобразования типов выносится в отдельную функцию, а основной цикл остается простым и понятным.
Если структура вашего JSON-файла жестко регламентирована и у вас есть соответствующая схема (XSD), можно рассмотреть еще более продвинутый метод — использование ФабрикиXDTO. Метод ФабрикаXDTO.ПрочитатьJSON() также умеет работать с объектом ЧтениеJSON.
Это бывает полезно, когда нужно автоматически типизировать данные согласно метаданным вашей конфигурации. Однако гибридное чтение через ПрочитатьJSON() в структуру является более гибким и часто используемым в повседневных задачах интеграции.
Мы выяснили, что утверждение о невозможности совмещения потокового и объектного чтения в 1С является ошибочным. Платформа предоставляет мощный инструмент для "выкусывания" фрагментов из потока данных. Используя связку ЧтениеJSON для внешнего цикла и ПрочитатьJSON() для внутренней структуры, вы получаете высокую скорость разработки при минимальном потреблении памяти.