Смотрим, что лежит в массиве 1С 8.3: от цикла с сообщениями до JSON и журнала регистрации

· 10 мин

Содержание

Чтобы вывести значение массива в 1С, переберите его циклом Для Каждого Элемент Из Массив Цикл и передайте каждый элемент в Сообщить(). Если элементы — строки, хватит одной строки кода: Сообщить(СтрСоединить(Массив, ", ")). А вот Сообщить(Массив) покажет только слово «Массив»: платформа выводит представление типа, а не содержимое.

Дальше всё зависит от задачи. Нужно глянуть один раз при отладке — точка останова и окно вычисления выражений. Нужно показать пользователю — таблица или список на форме. Нужно передать или сохранить сложную структуру — JSON. Все примеры рассчитаны на платформу 8.3 с управляемыми формами.

Сообщить() и СтрСоединить: самый быстрый вывод массива

Базовый способ работает везде: в обработке, в модуле формы, в общем модуле на сервере. Сообщения с сервера платформа сама передаёт клиенту, и они появляются в окне сообщений внизу формы.

Цикл по элементам

Массив = Новый Массив;
Массив.Добавить("Иванов");
Массив.Добавить("Петров");
Массив.Добавить("Сидоров");

Для Каждого Элемент Из Массив Цикл
    Сообщить(Элемент);
КонецЦикла;

Если нужен ещё и номер элемента, используйте цикл по индексу. Нумерация в массиве 1С начинается с нуля, последний индекс возвращает ВГраница():

Для Индекс = 0 По Массив.ВГраница() Цикл
    Сообщить(СтрШаблон("[%1] %2", Индекс, Массив[Индекс]));
КонецЦикла;

Результат: [0] Иванов, [1] Петров, [2] Сидоров. У пустого массива ВГраница() возвращает -1, поэтому цикл просто не выполнится — отдельная проверка не нужна.

Одна строка вместо цикла

Функция СтрСоединить() появилась в платформе 8.3.6. Она склеивает массив строк через разделитель:

Сообщить(СтрСоединить(Массив, ", "));
// Иванов, Петров, Сидоров

Сообщить(СтрСоединить(Массив, Символы.ПС));
// каждый элемент с новой строки

Длинный массив выводите одним сообщением через Символы.ПС, а не тысячей отдельных Сообщить(). Окно сообщений на 10 000 строк заметно тормозит клиент, а одно длинное сообщение открывается сразу.

СтрСоединить() рассчитана на строки. Если в массиве числа, даты или ссылки, сначала соберите массив представлений:

Представления = Новый Массив;
Для Каждого Элемент Из Массив Цикл
    Представления.Добавить(Строка(Элемент));
КонецЦикла;
Сообщить(СтрСоединить(Представления, "; "));

СообщениеПользователю вместо Сообщить

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

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрСоединить(Массив, ", ");
Сообщение.Сообщить();

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

Окно сообщений годится для разработчика. Пользователю удобнее увидеть значения массива в таблице, которую можно отсортировать и скопировать.

Через список значений

Самый короткий путь — список значений. Метод ЗагрузитьЗначения() переносит в него весь массив, а ПоказатьВыборЭлемента() открывает окно со списком без создания отдельной формы:

&НаКлиенте
Процедура ПоказатьМассив(Команда)
    Массив = ПолучитьМассивНаСервере();
    Список = Новый СписокЗначений;
    Список.ЗагрузитьЗначения(Массив);
    Список.ПоказатьВыборЭлемента(, "Содержимое массива");
КонецПроцедуры

Обратно в массив список превращается методом ВыгрузитьЗначения().

Через таблицу значений

Если у каждого элемента нужно показать несколько колонок (индекс, значение, тип), соберите таблицу значений на сервере:

&НаСервере
Процедура ЗаполнитьТаблицуНаСервере()
    Массив = ПолучитьДанные();

    ТЗ = Новый ТаблицаЗначений;
    ТЗ.Колонки.Добавить("Индекс");
    ТЗ.Колонки.Добавить("Значение");
    ТЗ.Колонки.Добавить("Тип");

    Для Индекс = 0 По Массив.ВГраница() Цикл
        НоваяСтрока = ТЗ.Добавить();
        НоваяСтрока.Индекс   = Индекс;
        НоваяСтрока.Значение = Массив[Индекс];
        НоваяСтрока.Тип      = Строка(ТипЗнч(Массив[Индекс]));
    КонецЦикла;

    ЗначениеВРеквизитФормы(ТЗ, "ТаблицаМассива");
КонецПроцедуры

Чтобы код заработал, в форме заранее создайте реквизит ТаблицаМассива с типом ТаблицаЗначений и колонками с теми же именами, а затем перетащите его на форму. Колонки, добавленные только в коде, на форме сами не появятся.

Таблицу значений нельзя передать на клиент как есть. На форме она живёт как ДанныеФормыКоллекция, поэтому заполняйте её на сервере и переносите через ЗначениеВРеквизитФормы().

Через табличный документ

Для печати или выгрузки в Excel выведите массив в ТабличныйДокумент. Без макета это делается через область по координатам:

ТабДок = Новый ТабличныйДокумент;
Для Индекс = 0 По Массив.ВГраница() Цикл
    ТабДок.Область(Индекс + 1, 1).Текст = Строка(Индекс);
    ТабДок.Область(Индекс + 1, 2).Текст = Строка(Массив[Индекс]);
КонецЦикла;
ТабДок.Показать("Массив");

Строки табличного документа нумеруются с единицы, отсюда Индекс + 1.

Отладчик 1С: посмотреть элементы массива без единой строки кода

Для разработчика это самый быстрый способ. Код менять не надо, ничего потом не придётся удалять из модуля.

  1. Откройте модуль в конфигураторе или EDT и поставьте точку останова на строку после заполнения массива — клавиша F9.
  2. Запустите отладку F5 и выполните действие, которое вызывает этот код.
  3. Когда выполнение остановится, выделите имя переменной и нажмите Shift+F9 — откроется окно вычисления выражения.
  4. Раскройте узел массива: элементы показаны по индексам, у каждого видны значение и тип.

Вложенные структуры, соответствия и объекты раскрываются так же, по уровням. Переменную можно добавить в табло, и она будет обновляться при каждом шаге (F10, F11).

В окне вычисления можно писать выражения, а не только имена: Массив.Количество(), Массив[5], Массив.Найти("Петров"). Последнее вернёт индекс элемента или Неопределено, если такого значения нет.

Если массив огромный и искать нужный элемент глазами долго, вычислите в том же окне СтрСоединить(Массив, Символы.ПС) и скопируйте результат в текстовый редактор.

Отладка на сервере должна быть разрешена. В файловой базе она работает сразу. В клиент-серверной базе сервер запускают с ключом -debug, иначе точки останова в серверном коде не сработают.

JSON: вывод массива со вложенными структурами

Когда в массиве лежат структуры, другие массивы или соответствия, построчный Сообщить() неудобен. JSON выводит всё дерево целиком и с отступами:

Функция МассивВJSON(Значение)
    Параметры = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, Символы.Таб);
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку(Параметры);
    ЗаписатьJSON(Запись, Значение);
    Возврат Запись.Закрыть();
КонецФункции

Товар = Новый Структура("Код, Наименование, Цена", "00012", "Бумага А4", 450);
Массив = Новый Массив;
Массив.Добавить(Товар);
Массив.Добавить(Новый Структура("Код, Наименование, Цена", "00031", "Скобы", 85));

Сообщить(МассивВJSON(Массив));

Вывод:

[
	{
		"Код": "00012",
		"Наименование": "Бумага А4",
		"Цена": 450
	},
	{
		"Код": "00031",
		"Наименование": "Скобы",
		"Цена": 85
	}
]

ЗаписатьJSON() понимает строки, числа, булево, даты, Неопределено, а также Массив, Структура, Соответствие и их фиксированные варианты. У соответствия ключи должны быть строками.

Ссылки на справочники и документы напрямую в JSON не записываются — платформа выдаст ошибку о том, что тип не поддерживается. Есть два выхода:

  • 🔹 перед записью заменить ссылки на строки или уникальные идентификаторы: Строка(Ссылка) или Строка(Ссылка.УникальныйИдентификатор());
  • 🔹 для обмена между базами 1С использовать СериализаторXDTO.ЗаписатьJSON(): он записывает ссылки вместе с типом, а читающая база сможет их восстановить.

Для разового просмотра на сервере есть ещё ЗначениеВСтрокуВнутр(Массив). Строка получается во внутреннем формате 1С, читать её неудобно, зато сериализуются почти любые значения, включая ссылки.

Массив ссылок, структур и вложенных массивов

Сложнее всего вывести массив, у которого элементы — не строки. От типа элемента зависит, что покажет Строка():

Что в массивеЧто выведет Строка(Элемент)Как вывести нормально
Ссылка на справочник или документПредставление: «Бумага А4», «Реализация 0000-000123 от 15.03…»Как есть или нужный реквизит через точку
СтруктураСлово «Структура»Цикл по КлючИЗначение или JSON
СоответствиеСлово «Соответствие»Цикл по КлючИЗначение
Вложенный массивСлово «Массив»Рекурсия или JSON
Число«1 234,5» с разделителем группФормат(Число, "ЧГ=0")
Булево«Да» или «Нет»Как есть
НеопределеноПустая строкаЯвная проверка на Неопределено

Ссылки: не читайте реквизиты в цикле

У массива ссылок есть ловушка производительности. Каждое обращение Элемент.Наименование или Элемент.ИНН на сервере — это отдельное чтение из базы. На 5 000 элементов получится 5 000 запросов.

Правильно — получить реквизиты одним запросом:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Контрагенты.Ссылка,
|    Контрагенты.ИНН
|ИЗ
|    Справочник.Контрагенты КАК Контрагенты
|ГДЕ
|    Контрагенты.Ссылка В (&Массив)";
Запрос.УстановитьПараметр("Массив", МассивСсылок);

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(СтрШаблон("%1 — ИНН %2", Выборка.Ссылка, Выборка.ИНН));
КонецЦикла;

Массив можно передать в запрос параметром целиком: условие В (&Массив) его понимает. Справочник Контрагенты и реквизит ИНН есть в БП 3.0 и УТ 11; в своей конфигурации подставьте нужный объект.

Рекурсивный вывод любой вложенности

Если состав заранее неизвестен, поможет универсальная процедура. Она обходит массивы, структуры и соответствия и печатает каждый уровень с отступом:

Процедура ВывестиЗначение(Значение, Отступ = "")
    Тип = ТипЗнч(Значение);
    Если Тип = Тип("Массив") Или Тип = Тип("ФиксированныйМассив") Тогда
        Для Индекс = 0 По Значение.ВГраница() Цикл
            Сообщить(СтрШаблон("%1[%2]", Отступ, Индекс));
            ВывестиЗначение(Значение[Индекс], Отступ + "    ");
        КонецЦикла;
    ИначеЕсли Тип = Тип("Структура") Или Тип = Тип("Соответствие") Тогда
        Для Каждого КлючИЗначение Из Значение Цикл
            Сообщить(СтрШаблон("%1%2:", Отступ, КлючИЗначение.Ключ));
            ВывестиЗначение(КлючИЗначение.Значение, Отступ + "    ");
        КонецЦикла;
    ИначеЕсли Значение = Неопределено Тогда
        Сообщить(Отступ + "<Неопределено>");
    Иначе
        Сообщить(Отступ + Строка(Значение));
    КонецЕсли;
КонецПроцедуры

Для большого дерева замените Сообщить() на добавление строк в массив и выведите его в конце одним СтрСоединить().

Многомерный массив

Конструктор Новый Массив(3, 4) создаёт массив из трёх элементов, каждый из которых — массив из четырёх. Выводят его двумя вложенными циклами, обращение к элементу — Матрица[Строка][Колонка]:

Для Ряд = 0 По Матрица.ВГраница() Цикл
    Значения = Новый Массив;
    Для Колонка = 0 По Матрица[Ряд].ВГраница() Цикл
        Значения.Добавить(Строка(Матрица[Ряд][Колонка]));
    КонецЦикла;
    Сообщить(СтрСоединить(Значения, " | "));
КонецЦикла;

Файл и журнал регистрации: когда сообщений не видно

Окна сообщений нет у фонового задания, регламентного задания и HTTP-сервиса. Значения массива там пишут в файл или в журнал регистрации.

Текстовый файл

Текст = Новый ТекстовыйДокумент;
Для Индекс = 0 По Массив.ВГраница() Цикл
    Текст.ДобавитьСтроку(СтрШаблон("%1;%2", Индекс, Массив[Индекс]));
КонецЦикла;
Текст.Записать(ПолучитьИмяВременногоФайла("csv"), КодировкаТекста.UTF8);

Код выполняется на той машине, где он запущен. Серверный код запишет файл на сервер 1С, а не на компьютер пользователя. Учётной записи службы сервера нужны права на запись в каталог.

Журнал регистрации

ЗаписьЖурналаРегистрации("Отладка.Массив",
    УровеньЖурналаРегистрации.Информация, , ,
    СтрСоединить(Представления, Символы.ПС));

Запись найдётся по имени события через отбор журнала регистрации: Администрирование → Обслуживание → Журнал регистрации в БП 3.0 и УТ 11. Удобно для регламентных заданий: видно время и пользователя.

Отладочные записи в журнал удалите из кода после проверки. Регламентное задание, которое каждые 5 минут пишет массив на 10 000 строк, быстро раздувает журнал.

Внешняя обработка для экспериментов

Проверять вывод массива удобно во внешней обработке: создайте форму с кнопкой, вставьте код и откройте файл .epf через Файл → Открыть в режиме 1С:Предприятие. Конфигурацию менять не нужно. Внешние компоненты (Native API) для такой задачи избыточны: они нужны для работы с оборудованием и сторонними библиотеками, а не для вывода данных.

Какой способ выбрать

ЗадачаСпособОграничение
Быстро глянуть при разработкеОтладчик, Shift+F9Нужна разрешённая отладка
Вывести строки одной фразойСтрСоединить()Платформа 8.3.6 и выше, только строки
Показать пользователюСписок или таблица на формеРеквизит формы создаётся заранее
Сложная вложенная структураJSONСсылки нужно преобразовать
Фоновое или регламентное заданиеЖурнал регистрации или файлФайл пишется на сервер

Почему не выводится массив: частые ошибки

Диагностика: выберите симптом

Ещё одна частая ошибка — удаление элементов массива в прямом цикле по индексу. После каждого Удалить() элементы сдвигаются, и следующий пропускается. Удаляйте с конца:

Для Сч = 1 По Массив.Количество() Цикл
    Индекс = Массив.Количество() - Сч;
    Если ПустаяСтрока(Массив[Индекс]) Тогда
        Массив.Удалить(Индекс);
    КонецЕсли;
КонецЦикла;

Граница цикла вычисляется один раз при входе, а индекс считается от текущего количества элементов, поэтому каждый элемент проверяется ровно один раз.

Частые вопросы

Как узнать, сколько элементов в массиве?
Метод Массив.Количество(). Для пустого массива он вернёт 0, а ВГраница() вернёт -1.
Как вывести только уникальные значения массива?
Загрузите массив в таблицу значений с одной колонкой и вызовите Свернуть("Значение"), затем ВыгрузитьКолонку("Значение"). В БСП есть готовая функция ОбщегоНазначенияКлиентСервер.СвернутьМассив().
Можно ли вывести массив, полученный из запроса?
Да. РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка") вернёт массив значений колонки. Дальше выводите его циклом, через СтрСоединить() или в JSON.
Как отсортировать массив перед выводом?
У массива нет метода сортировки. Загрузите значения в СписокЗначений и вызовите СортироватьПоЗначению(), затем ВыгрузитьЗначения().
Почему Сообщить() на сервере ничего не показывает?
Сообщения с сервера доходят до клиента после завершения серверного вызова. Если вызов идёт из фонового задания или HTTP-сервиса, клиента нет — используйте журнал регистрации.