Как правильно записывать и читать JSON в 1С: решаем проблему с null в массивах и ошибками состояния потока

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

Работа с форматом JSON в платформе 1С:Предприятие 8.3 — задача стандартная, но имеющая множество подводных камней. Начинающие разработчики часто сталкиваются с ситуациями, когда вместо ожидаемых данных в файле появляются значения null, или система выдает загадочную ошибку "Недопустимое состояние потока записи JSON". В рамках данной статьи мы подробно разберем, как избежать этих проблем, проанализируем разницу между методами коллекций и научимся формировать валидные структуры данных для обмена с внешними системами.

Разбираем причину появления null в массиве JSON

Рассмотрим ситуацию, когда при записи массива строк вы получаете результат вида [null, null, null, "значение"]. Выясним причину такого поведения. В 1С у объекта Массив есть два основных метода добавления данных: Добавить() и Вставить(). Ошибка часто кроется в использовании второго метода.

Метод Вставить(Индекс, Значение) предназначен для помещения элемента в конкретную позицию. Если вы ошибочно передаете туда данные или используете индексы, которые «разрывают» последовательность, 1С заполняет пустые места значениями Неопределено. При сериализации в JSON эти значения превращаются в null.

Проанализируем правильный подход. Для формирования простого списка значений всегда используйте метод Добавить(). Посмотрим на пример кода:


// Неправильный подход, который может привести к null
МассивДанных = Новый Массив;
МассивДанных.Вставить(0, "114973"); // Если перепутать параметры или индексы, будет брак

// Правильный подход
МассивДанных = Новый Массив;
МассивДанных.Добавить("114973");
МассивДанных.Добавить("114974");
МассивДанных.Добавить("114975");

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МассивДанных);
Результат = ЗаписьJSON.Закрыть();

Важный момент: если вы используете высокоуровневый метод ЗаписатьJSON(), система сама заботится об открытии и закрытии всех скобок массива. Попытка вручную «дорисовать» элементы часто приводит к нарушению структуры.

Ошибка "Недопустимое состояние потока": почему она возникает?

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

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

  1. Инициализируем объект ЗаписьJSON.
  2. Устанавливаем назначение (строка или файл).
  3. Выполняем запись данных (через ЗаписатьJSON или низкоуровневые методы).
  4. Только после завершения всех операций вызываем Закрыть().

Если вам нужно прочитать только что созданный JSON, необходимо создать новый объект ЧтениеJSON, как показано в примере ниже:


// Код записи
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, МоиДанные);
СтрокаJSON = Запись.Закрыть(); // После этого "Запись" использовать нельзя!

// Код чтения
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(СтрокаJSON);
Результат = ПрочитатьJSON(Чтение);
Чтение.Закрыть();

Структура против Соответствия: как работать с числовыми ключами

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

Если ваша задача — получить JSON вида {"114973": {...}}, то Структура не подойдет, так как ключ "114973" недопустим. В этом случае мы должны использовать объект Соответствие (Map). Рассмотрим пример создания такой коллекции:


ДанныеДоговоров = Новый Соответствие;

Для Каждого Строка Из ТаблицаДанных Цикл
    Детали = Новый Структура;
    Детали.Вставить("policy_no", Строка.Номер);
    Детали.Вставить("insuranced_at", Формат(Строка.Дата, "ДФ=dd.MM.yyyy"));
    
    // Используем номер договора как ключ в Соответствии
    ДанныеДоговоров.Вставить(Строка.НомерДоговора, Детали);
КонецЦикла;

// При записи Соответствие превратится в объект JSON с ключами-строками
ЗаписатьJSON(ЗаписьJSON, ДанныеДоговоров);

Валидность JSON: Массив или Объект?

Иногда внешние системы требуют странные форматы, например: [ "договор1": { ... } ]. Посмотрим на эту структуру внимательно: это невалидный JSON. В стандарте JSON массив (квадратные скобки) может содержать только перечисление значений, но не пары "ключ: значение". Именованные свойства могут быть только внутри объекта (фигурные скобки).

Если вам нужно передать список именованных объектов, у вас есть два пути:

  1. Массив объектов: [ {"номер": "договор1", "данные": {...}}, {"номер": "договор2", "...": ...} ].
  2. Один корневой объект: { "договор1": {...}, "договор2": {...} }.

Попытки «убрать лишнюю запятую» вручную в коде формирования текста обычно сигнализируют о том, что выбран неправильный тип коллекции 1С. Помните: Массив в 1С — это [] в JSON, а Структура или Соответствие — это {}.

Низкоуровневая запись: когда автоматики недостаточно

Рассмотрим ситуацию, когда вам нужно очень точно контролировать процесс записи, например, при формировании огромных файлов, которые не помещаются в оперативную память целиком. В этом случае мы отказываемся от метода ЗаписатьJSON(Запись, Объект) и используем пошаговую запись.

Проанализируем пример ручного формирования структуры:


ЗаписьJSON.ЗаписатьНачалоМассива(); // Пишет [

Для Каждого Элемент Из СписокДоговоров Цикл
    ЗаписьJSON.ЗаписатьНачалоОбъекта(); // Пишет {
    
    ЗаписьJSON.ЗаписатьИмяСвойства("id");
    ЗаписьJSON.ЗаписатьЗначение(Элемент.Идентификатор);
    
    ЗаписьJSON.ЗаписатьИмяСвойства("data");
    ЗаписьJSON.ЗаписатьНачалоОбъекта();
    // ... запись вложенных свойств
    ЗаписьJSON.ЗаписатьКонецОбъекта();
    
    ЗаписьJSON.ЗаписатьКонецОбъекта(); // Пишет }
КонецЦикла;

ЗаписьJSON.ЗаписатьКонецМассива(); // Пишет ]

Важное правило: Каждому вызову ЗаписатьНачалоОбъекта должен соответствовать ЗаписатьКонецОбъекта. Если вы нарушите вложенность, 1С выдаст ошибку состояния потока при попытке завершить запись.

Почему не стоит собирать JSON строками?

Иногда возникает соблазн просто складывать строки: СтрокаJSON = "[" + " { " + .... Мы настоятельно рекомендуем избегать этого метода. Рассмотрим причины:

Настройка чтения JSON

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

Чтобы этого избежать, всегда указывайте четвертый параметр метода — тип читаемого объекта:


// Указываем, что объекты JSON нужно читать в Соответствие, а не в Структуру
Результат = ПрочитатьJSON(ЧтениеJSON, Ложь, , "Соответствие");

Это обеспечит максимальную совместимость с любыми внешними API, независимо от того, какие имена полей они используют.

← На главную