Оптимизация пакетной передачи больших объемов данных через JSON-потоки в 1С
При выгрузке или загрузке больших файлов JSON (сотни мегабайт/гигабайты) возникают проблемы:
- Аварийное завершение процесса
rphostс ошибкойНедостаточно свободной памяти (Out of memory). - Функция
ПрочитатьJSON()илиЗаписатьJSON()зависает при попытке десериализации дерева структур целиком в ОЗУ. - Превышение лимита памяти на рабочий процесс 1С и принудительный перезапуск сеанса сервером кластера.
1. Разница между объектной и потоковой обработкой JSON
Метод ПрочитатьJSON(ЧтениеJSON) загружает весь документ в виде единого объекта (Структура / Соответствие / Массив), что требует объема ОЗУ в 5-10 раз больше размера самого JSON-файла. Потоковое чтение (Streaming API) считывает файл токен за токеном, удерживая в памяти только один текущий элемент.
2. Потоковая генерация JSON-файла большого объема
&НаСервере
Процедура ВыгрузитьНоменклатуруВПотокJSON(ИмяФайлаВыгрузки)
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ", Истина);
ЗаписьJSON.ОткрытьФайл(ИмяФайлаВыгрузки, КодировкаТекста.UTF8, , ПараметрыЗаписи);
ЗаписьJSON.ЗаписатьНачалоОбъекта();
ЗаписьJSON.ЗаписатьИмяСвойства("version");
ЗаписьJSON.ЗаписатьЗначение("2.0");
ЗаписьJSON.ЗаписатьИмяСвойства("items");
ЗаписьJSON.ЗаписатьНачалоМассива();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ЗаписьJSON.ЗаписатьНачалоОбъекта();
ЗаписьJSON.ЗаписатьИмяСвойства("guid");
ЗаписьJSON.ЗаписатьЗначение(Строка(Выборка.Ссылка.УникальныйИдентификатор()));
ЗаписьJSON.ЗаписатьИмяСвойства("code");
ЗаписьJSON.ЗаписатьЗначение(Выборка.Код);
ЗаписьJSON.ЗаписатьИмяСвойства("name");
ЗаписьJSON.ЗаписатьЗначение(Выборка.Наименование);
ЗаписьJSON.ЗаписатьИмяСвойства("article");
ЗаписьJSON.ЗаписатьЗначение(Выборка.Артикул);
ЗаписьJSON.ЗаписатьКонецОбъекта();
КонецЦикла;
ЗаписьJSON.ЗаписатьКонецМассива();
ЗаписьJSON.ЗаписатьКонецОбъекта();
ЗаписьJSON.Закрыть();
КонецПроцедуры3. Потоковое чтение огромных файлов JSON
&НаСервере
Процедура ЗагрузитьБольшойJSON(ИмяФайла)
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьФайл(ИмяФайла, КодировкаТекста.UTF8);
// Позиционирование на массиве элементов
Пока ЧтениеJSON.Прочитать() Цикл
Если ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.ИмяСвойства И ЧтениеJSON.ТекущееЗначение = "items" Тогда
Прервать;
КонецЕсли;
КонецЦикла;
// Пропускаем начало массива
ЧтениеJSON.Прочитать();
// Потоковая десериализация каждого объекта массива по отдельности
Пока ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.НачалоОбъекта Цикл
// Считываем только один элемент в структуру
ТоварСтруктура = ПрочитатьJSON(ЧтениеJSON, Ложь);
// Бизнес-логика обработки элемента без накопления в ОЗУ
ОбработатьОдинТовар(ТоварСтруктура);
КонецЦикла;
ЧтениеJSON.Закрыть();
КонецПроцедуры Частые вопросы (FAQ)
Почему ЗаписьJSON.Закрыть() является обязательным вызовом?
Метод Закрыть() сбрасывает накопленный дисковый буфер из оперативной памяти в файл и освобождает дескриптор операционной системы. Без вызова Закрыть() файл останется заблокированным и неполным.
Как сериализовать дату 1С в стандартный ISO 8601 в JSON?
Передайте формат даты в метод ЗаписатьЗначение(Дата, ФорматДатыJSON.ISO) или укажите ФорматДатыJSON.ISO в объекте ПараметрыЗаписиJSON.
Какой объем ОЗУ потребляет потоковое чтение?
Потоковое чтение потребляет константный объем памяти (обычно не более нескольких мегабайт), независимо от того, весит ли исходный JSON-файл 100 МБ или 50 ГБ.
Как пропустить ненужные вложенные узлы при потоковом чтении?
Используйте метод ЧтениеJSON.Пропустить(), который автоматически перемещает указатель в конец текущего объекта или массива без разбора дочерних свойств.