В практике разработки на платформе 1С часто возникает задача выгрузки данных во внешние системы или файлы. Стандартный подход, когда мы выполняем запрос, обходим выборку циклом и заполняем какой-то промежуточный объект, не всегда эффективен. Особенно это касается случаев, когда данных много, или когда требуется минимизировать количество кода. Для решения таких задач часто используют универсальный инструмент для высокопроизводительной выгрузки, такой как модуль «Трансформер» для конвертации JSON/XML/CSV/TOON, который позволяет работать напрямую с форматами Excel и CSV на стороне сервера.
Рассмотрим подробно, как можно сохранить результат запроса в файл различными способами (поможет универсальная выгрузка данных из 1С в Excel), используя как встроенные механизмы сериализации, так и методы потоковой записи. Мы разберем примеры для форматов JSON, Excel и CSV, проанализируем преимущества и недостатки каждого подхода.
Один из самых лаконичных способов получить файл JSON из запроса — использование глобального объекта СериализаторXDTO. Этот метод удобен тем, что позволяет преобразовать плоскую таблицу (результат запроса или Таблицу Значений) в формат JSON буквально в несколько строк кода. Детально этот процесс описан в руководстве по работе с JSON в 1С:8.3. Подобные механизмы лежат в основе инструментов, через которые реализуется экспорт любых документов базы в JSON с сохранением всей бизнес-логики.
Суть метода заключается в предварительной выгрузке результата запроса в ТаблицаЗначений, а затем передаче этой таблицы в метод записи сериализатора. Таким же образом можно реализовать и более специфические задачи, например, выгрузку метаданных в JSON для описания структуры конфигурации.
Давайте посмотрим на программный код реализации этого метода:
// 1. Подготавливаем запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 100
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
// 2. Выгружаем результат в Таблицу Значений
// Обратите внимание: этот метод загружает все данные в оперативную память
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
// 3. Настраиваем запись JSON
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку(); // Или Запись.ОткрытьФайл("ПутьКФайлу.json");
// 4. Используем СериализаторXDTO для автоматического преобразования
СериализаторXDTO.ЗаписатьJSON(Запись, ТаблицаДанных);
// 5. Получаем результат (если писали в строку)
РезультатJSON = Запись.Закрыть();
Преимущества:
Недостатки:
Основной минус данного подхода — необходимость выгрузки результата запроса в ТаблицаЗначений через метод Выгрузить(). Если выборка содержит десятки или сотни тысяч строк, это может привести к значительному потреблению оперативной памяти сервера, так как вся таблица должна быть построена в памяти целиком перед записью.
Если перед нами стоит задача выгрузить очень большой объем данных, метод с промежуточной таблицей значений может вызвать ошибку нехватки памяти. Чтобы обойти эти ограничения, можно использовать оптимизированные методы выгрузки данных, которые позволяют обрабатывать огромные выборки запросов. В этом случае мы должны использовать потоковую запись: обходить выборку запроса и записывать данные в файл построчно.
Разберем, как это реализовать, используя объект ЗаписьJSON внутри цикла обхода выборки:
Запрос = Новый Запрос("ВЫБРАТЬ Номенклатура, Артикул ИЗ Справочник.Номенклатура");
Выборка = Запрос.Выполнить().Выбрать();
Запись = Новый ЗаписьJSON;
Запись.ОткрытьФайл("C:\Exchange\Export.json");
// Начинаем массив данных
Запись.ЗаписатьНачалоМассива();
Пока Выборка.Следующий() Цикл
// Для каждой строки выборки создаем объект JSON
Запись.ЗаписатьНачалоОбъекта();
// Записываем свойства
Запись.ЗаписатьИмяСвойства("Nomenclature");
Запись.ЗаписатьЗначение(Выборка.Номенклатура.Наименование); // Приводим к строке при необходимости
Запись.ЗаписатьИмяСвойства("Article");
Запись.ЗаписатьЗначение(Выборка.Артикул);
Запись.ЗаписатьКонецОбъекта();
КонецЦикла;
// Закрываем массив
Запись.ЗаписатьКонецМассива();
Запись.Закрыть();
Этот подход не требует выделения памяти под полную таблицу данных. Мы формируем файл "на лету". Это наиболее надежный способ для промышленных объемов данных.
Для сохранения результата запроса в табличный документ (Excel, MXL) часто используют объект ПостроительОтчета. Несмотря на то, что этот объект считается устаревающим, он все еще отлично подходит для быстрой выгрузки плоских таблиц напрямую из результата запроса и доступен для выполнения на сервере. Это часто применяется в готовых решениях, когда требуется экспорт справочников в Excel с фильтрами без создания сложных макетов.
Особенность ПостроительОтчета в том, что он умеет принимать в качестве источника данных результат запроса напрямую, без промежуточной выгрузки в ТЗ. Подобным методом также может быть реализована выгрузка журнала регистрации в Excel с группировкой для последующего анализа администратором.
Посмотрим на реализацию:
// Получаем результат запроса (не выгружая в ТЗ!)
РезультатЗапроса = Запрос.Выполнить();
// Создаем описание источника данных на основании результата
ИсточникДанных = Новый ОписаниеИсточникаДанных(РезультатЗапроса);
// Инициализируем построитель
Построитель = Новый ПостроительОтчета;
Построитель.ИсточникДанных = ИсточникДанных;
// Формируем внутреннюю структуру отчета
Построитель.Выполнить();
// Выводим данные в Табличный Документ
ТабДок = Новый ТабличныйДокумент;
Построитель.Вывести(ТабДок);
// Сохраняем в файл XLSX
ТабДок.Записать(КаталогВременныхФайлов() + "Export.xlsx", ТипФайлаТабличногоДокумента.XLSX);
Этот метод удобен тем, что ПостроительОтчета автоматически генерирует заголовки колонок на основе полей запроса (или их псевдонимов). Это избавляет нас от ручного рисования макетов.
В современных конфигурациях на управляемых формах более правильным с архитектурной точки зрения считается использование Системы Компоновки Данных (СКД). Этот способ сложнее в написании, но он позволяет реализовать программный вывод СКД в табличный документ с сохранением сложного оформления, группировок и итогов.
Мы можем программно скомпоновать макет и вывести его в табличный документ:
// 1. Создаем схему компоновки (или берем из макета)
СхемаКомпоновки = Новый СхемаКомпоновкиДанных;
Источник = СхемаКомпоновки.ИсточникиДанных.Добавить();
Источник.Имя = "ИсточникДанных";
Источник.ТипИсточникаДанных = "Local";
НаборДанных = СхемаКомпоновки.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
НаборДанных.Запрос = Запрос.Текст;
// ... (далее следует настройка полей набора данных) ...
// 2. Инициализируем процессор компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Новый НастройкиКомпоновкиДанных);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// 3. Выводим результат
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// 4. Сохраняем
ТабДок.Записать("C:\Report.xlsx", ТипФайлаТабличногоДокумента.XLSX);
Использование СКД предпочтительнее, если вам нужно не просто выгрузить "сырые" данные, а применить оформление перед сохранением в файл. Для этой задачи есть инструменты разработчика для запросов и СКД.
Часто для интеграции требуется самый простой формат — CSV. Здесь лучше всего использовать объект ЗаписьТекста. Чтобы избежать типичных ошибок при формировании таких файлов, рекомендуем изучить алгоритмы работы с CSV файлами, включая вопросы кодировок и экранирования спецсимволов. Если же вам нужно не создавать файл, а выполнить обратное действие или преобразование, может пригодиться специализированный конвертор файлов из CSV в XLS.
Разберем алгоритм построчной записи:
Запрос = Новый Запрос(...);
Выборка = Запрос.Выполнить().Выбрать();
Текст = Новый ЗаписьТекста("C:\Export.csv", КодировкаТекста.ANSI);
// Записываем заголовки, если нужно
Текст.ЗаписатьСтроку("Номенклатура;Штрихкод;Количество");
Пока Выборка.Следующий() Цикл
// Формируем строку вручную, соединяя поля разделителем
СтрокаДанных = Строка(Выборка.Номенклатура) + ";" +
Строка(Выборка.Штрихкод) + ";" +
XMLСтрока(Выборка.Количество); // XMLСтрока полезна для чисел, чтобы разделитель не зависел от локали
Текст.ЗаписатьСтроку(СтрокаДанных);
КонецЦикла;
Текст.Закрыть();
Важные моменты при работе с CSV:
;, структура файла нарушится. В таких случаях данные нужно оборачивать в кавычки или экранировать.XMLСтрока() для числовых полей и дат, чтобы формат записи (например, разделитель дробной части) был стандартным и не зависел от настроек операционной системы пользователя.Подведем итог выбора метода в зависимости от вашей задачи:
СериализаторXDTO и выгрузку в Таблицу Значений (Пример из Способа 1). Это быстро в разработке.ЗаписьJSON в цикле выборки (Способ 2). Это экономит память.ПостроительОтчета (Способ 3). Он принимает результат запроса напрямую.ЗаписьТекста и конкатенацию строк (Способ 5).Используя эти шаблоны кода, вы сможете эффективно решать задачи интеграции и выгрузки данных, не перегружая сервер лишними операциями преобразования типов.