Как в 1С при чтении JSON совместить потоковый и объектный подходы?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с внешними системами обмена данными программисты 1С часто сталкиваются с файлами JSON огромного объема (сотни мегабайт или даже несколько гигабайт). Основная проблема заключается в том, что стандартный объектный метод чтения ПрочитатьJSON() при загрузке всего файла целиком пытается поместить все данные в оперативную память. Если файл велик, это неизбежно приводит к ошибке "Недостаточно памяти" или критическому замедлению работы сервера.

С другой стороны, чисто потоковое чтение (через объект ЧтениеJSON и обход в цикле) крайне трудозатратно в разработке: программисту приходится вручную обрабатывать каждое событие начала объекта, чтения свойства и окончания массива. В этой статье мы подробно разберем, как найти "золотую середину" и использовать гибридный подход.

Постановка задачи: почему возникает сложность?

Рассмотрим стандартную ситуацию: мы получаем файл, который представляет собой огромный массив объектов (например, выгрузка товаров или остатков). Структура файла выглядит примерно так:


[
    {
        "ID": "00001",
        "Наименование": "Товар 1",
        "Цены": [ {"Тип": "Оптовая", "Цена": 100}, {"Тип": "Розничная", "Цена": 120} ],
        "Остатки": [ {"Склад": "Основной", "Количество": 10} ]
    },
    {
        "ID": "00002",
        "Наименование": "Товар 2",
        ...
    }
]

Если мы будем читать это потоком, нам придется писать десятки строк кода, чтобы "поймать" начало массива "Цены", затем в цикле читать каждый объект цены, проверять свойства и так далее. Это сложно отлаживать и поддерживать. Мы хотим читать глобальный массив потоково (по одному товару за раз), а внутреннюю структуру товара (свойства, вложенные массивы) получать сразу в виде удобной Структуры или Соответствия 1С.

Разбор решения: гибридный метод чтения

Решение существует в самой платформе 1С:Предприятие 8.3, хотя оно не всегда очевидно из документации. Основной секрет заключается в том, что функция ПрочитатьJSON() может принимать в качестве источника данных не только ЧтениеТекста, но и уже инициализированный объект ЧтениеJSON, который находится в процессе работы.

Проанализируем алгоритм работы этого метода:

  1. Мы открываем файл для потокового чтения.
  2. Запускаем цикл, пока поток не закончится.
  3. Как только указатель потока доходит до начала нужного нам элемента (объекта товара), мы "передаем управление" объектному методу.
  4. Метод ПрочитатьJSON(ЧтениеJSON) вычитывает ровно один текущий объект целиком, превращает его в структуру 1С и останавливается.
  5. Указатель в потоке автоматически перемещается на позицию сразу после прочитанного объекта.
  6. Мы продолжаем цикл потокового чтения до следующего элемента.

Реализация кода для гибридного чтения

Рассмотрим практический пример кода, который реализует эту логику. Представим, что нам нужно обработать файл с товарами, не загружая его целиком в память.


// Инициализируем чтение файла
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл("C:\Exchange\HugeData.json");

// Читаем начало глобального массива [
ЧтениеJSON.Прочитать(); 

// Основной цикл потокового обхода
Пока ЧтениеJSON.Прочитать() Цикл
    
    // Проверяем, начался ли новый объект товара {
    Если ЧтениеJSON.ТипТекущегоЗначения = ТипТекущегоЗначенияJSON.НачалоОбъекта Тогда
        
        // ВАЖНЫЙ МОМЕНТ:
        // Мы вызываем объектное чтение для ОДНОГО элемента массива.
        // Платформа сама прочитает всё содержимое объекта до закрывающей скобки }
        // и вернет нам готовую структуру.
        
        ДанныеОбъекта = ПрочитатьJSON(ЧтениеJSON);
        
        // Теперь мы работаем с ДанныеОбъекта как с обычной структурой 1С
        ОбработатьДанныеТовара(ДанныеОбъекта);
        
        // После вызова ПрочитатьJSON, указатель ЧтениеJSON уже стоит 
        // на событии КонецОбъекта. Следующая итерация цикла .Прочитать()
        // переведет нас к следующему элементу массива.
        
    КонецЕсли;

КонецЦикла;

ЧтениеJSON.Закрыть();

Почему этот метод эффективен?

Проанализируем ситуацию с точки зрения потребления ресурсов. При таком подходе в оперативной памяти одновременно находится:

Сколько бы миллионов товаров ни было в файле, потребление памяти будет стабильным и низким, ограниченным лишь размером самого крупного одиночного объекта в массиве. Это позволяет обрабатывать файлы размером в несколько гигабайт даже на серверах с ограниченными ресурсами.

Обработка сложных типов (десериализация)

В Сообщении 8 форума поднимался вопрос: а что делать, если в JSON записаны данные, которые должны стать ссылками 1С (справочники, документы)?

При использовании гибридного метода мы можем задействовать второй параметр функции ПрочитатьJSON() — ФункцияВосстановленияДанных. Это позволяет нам на лету превращать строковые ГУИДы или коды в реальные ссылки 1С прямо в момент "захвата" объекта из потока.

Разберем, как это реализовать:


Функция ВосстановлениеДанных(Свойство, Значение, ДополнительныеПараметры) Экспорт
    Если Свойство = "ТоварСсылка" Тогда
        Возврат Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Значение));
    КонецЕсли;
    Возврат Значение;
КонецФункции

// В основном коде при вызове:
ДанныеОбъекта = ПрочитатьJSON(ЧтениеJSON, , "ВосстановлениеДанных", ЭтотОбъект);

Такой подход делает код чистым: логика преобразования типов выносится в отдельную функцию, а основной цикл остается простым и понятным.

Использование XDTO для строго заданных структур

Если структура вашего JSON-файла жестко регламентирована и у вас есть соответствующая схема (XSD), можно рассмотреть еще более продвинутый метод — использование ФабрикиXDTO. Метод ФабрикаXDTO.ПрочитатьJSON() также умеет работать с объектом ЧтениеJSON.

Это бывает полезно, когда нужно автоматически типизировать данные согласно метаданным вашей конфигурации. Однако гибридное чтение через ПрочитатьJSON() в структуру является более гибким и часто используемым в повседневных задачах интеграции.

Заключение

Мы выяснили, что утверждение о невозможности совмещения потокового и объектного чтения в 1С является ошибочным. Платформа предоставляет мощный инструмент для "выкусывания" фрагментов из потока данных. Используя связку ЧтениеJSON для внешнего цикла и ПрочитатьJSON() для внутренней структуры, вы получаете высокую скорость разработки при минимальном потреблении памяти.

← На главную