Выгрузка отчетности и прайс-листов из 1С в формат Microsoft Excel — одна из самых частых задач, с которыми сталкивается разработчик. Однако стандартного сохранения табличного документа не всегда достаточно. Иногда требуется сформировать сложную, «нелинейную» структуру строк, когда одна товарная позиция занимает несколько физических строк на листе, а рядом располагаются сопутствующие изображения или штрихкоды.
В этой статье мы подробно разберем, как решить проблему позиционирования при программном заполнении многострочных блоков через COM-объект Excel.Application, выясним, почему стандартный экспорт 1С может искажать (делать «мыльными») картинки товаров, и рассмотрим способы многократного ускорения выгрузки.
Представим ситуацию: нам необходимо выгрузить список номенклатуры в Excel. Каждая позиция должна представлять собой горизонтальную секцию (блок) высотой в две строки. Структура этого блока выглядит следующим образом:
Основная сложность у начинающих разработчиков заключается в правильном расчете индексов ячеек при обходе выборки в цикле. Если просто увеличивать счетчик строк на единицу, данные начнут накладываться друг на друга, затирая предыдущие значения.
Проанализируем типичную ошибку. Если мы используем шаг приращения строки, равный 1, то на следующей итерации цикла «Наименование» нового товара запишется поверх «Штрихкода» предыдущего товара. Чтобы этого не происходило, шаг приращения счетчика строк должен строго соответствовать физической высоте нашей горизонтальной секции — в данном случае это 2 строки.
Рассмотрим рабочий программный код, который позволяет корректно выводить двухстрочные блоки данных. Мы инициализируем стартовые позиции для строк наименования и штрихкода, а затем в цикле увеличиваем их на величину шага (равную 2):
// Инициализируем стартовые строки перед циклом
// Первая строка данных начнется с индекса 9, так как в цикле сразу идет прибавление шага
СтрокаНаименования = 7;
СтрокаШтрихкода = 8;
Для Каждого СтрокаТаблицы Из ОбщаяТаблицаДокументов Цикл
// Увеличиваем индексы строк на высоту нашей горизонтальной секции (2 строки)
СтрокаНаименования = СтрокаНаименования + 2;
СтрокаШтрихкода = СтрокаШтрихкода + 2;
// Заполняем ячейки первой строки блока
Лист.Cells(СтрокаНаименования, 2).Value = СтрокаТаблицы.Наименование;
Лист.Cells(СтрокаНаименования, 4).Value = СтрокаТаблицы.Артикул;
// Заполняем ячейку второй строки блока (строго под артикулом)
Лист.Cells(СтрокаШтрихкода, 4).Value = СтрокаТаблицы.Штрихкод;
КонецЦикла;
При таком подходе под каждый товар выделяется ровно две строки на листе Excel:
Часто разработчики отказываются от штатного метода сохранения табличного документа ТабличныйДокумент.Записать() в пользу COM-соединения из-за того, что при конвертации картинки (логотипы, штрихкоды, фотографии товаров) теряют исходное качество, становятся мутными и нечитаемыми. Это критично, например, для штрихкодов, которые после этого не могут распознать сканеры на складе.
Эту проблему можно решить штатными средствами 1С без использования медленного COM-соединения. Разберем основные правила сохранения четкости изображений:
РисунокТабличногоДокумента) обязательно должно быть установлено свойство РазмерКартинки в значение Растянуть (в коде это соответствует системному перечислению РазмерКартинки.Растянуть). Это заставит платформу экспортировать картинку в Excel в исходном физическом разрешении, без сжатия до размеров экранной сетки.ТипФайлаТабличногоДокумента.XLSX. Более старый формат XLS (Excel 97-2003) накладывает жесткие ограничения на палитру и сжимает графику по устаревшим алгоритмам, что неизбежно приводит к размытию картинок. В XLSX изображения сохраняются в их исходном сжатом виде внутри zip-архива документа.Если специфика бизнес-логики все же обязывает вас использовать COMОбъект("Excel.Application") (например, для выполнения сложных макросов или динамического форматирования «на лету»), помните, что построчная запись данных напрямую из 1С в каждую ячейку работает крайне медленно. При обработке более 1000 строк процесс может занять несколько минут.
Выясним, как ускорить этот процесс в десятки раз с помощью простых оптимизаций:
1. Отключение обновления экрана и автопересчета формул. Перед началом цикла заполнения обязательно переводите Excel в фоновый режим, отключайте визуальную отрисовку интерфейса и автоматический расчет формул. После завершения алгоритма возвращайте настройки в исходное состояние. Это экономит колоссальное количество ресурсов процессора:
ExcelПриложение = Новый COMОбъект("Excel.Application");
ExcelПриложение.Visible = Ложь;
// Отключаем обновление экрана для ускорения выгрузки
ExcelПриложение.ScreenUpdating = Ложь;
// Отключаем автоматический пересчет формул (ставим ручной режим)
ExcelПриложение.Calculation = -4135; // xlCalculationManual
// ... Ваш цикл заполнения ячеек ...
// Обязательно возвращаем настройки обратно по окончании работы
ExcelПриложение.ScreenUpdating = Истина;
ExcelПриложение.Calculation = -4105; // xlCalculationAutomatic
2. Использование двумерных массивов (COMSafeArray). Самый мощный способ оптимизации — минимизация обращений к COM-интерфейсу. Вместо записи в каждую ячейку по отдельности, сформируйте все данные в памяти 1С в виде специального массива COMSafeArray, а затем передайте его целиком в диапазон ячеек Range за один единственный вызов:
КоличествоСтрок = ОбщаяТаблицаДокументов.Количество() * 2;
КоличествоКолонок = 4;
// Создаем безопасный массив типа Variant
МассивДанных = Новый COMSafeArray("Variant", КоличествоСтрок, КоличествоКолонок);
ИндексСтроки = 0;
Для Каждого СтрокаТаблицы Из ОбщаяТаблицаДокументов Цикл
// Заполняем первую строку блока в массиве (индексы начинаются с 0)
МассивДанных.SetValue(ИндексСтроки, 1, СтрокаТаблицы.Наименование);
МассивДанных.SetValue(ИндексСтроки, 3, СтрокаТаблицы.Артикул);
// Заполняем вторую строку блока в массиве
МассивДанных.SetValue(ИндексСтроки + 1, 3, СтрокаТаблицы.Штрихкод);
ИндексСтроки = ИндексСтроки + 2;
КонецЦикла;
// Записываем весь массив в диапазон ячеек Excel за одну операцию
НачальнаяЯчейка = Лист.Cells(9, 1);
КонечнаяЯчейка = Лист.Cells(9 + КоличествоСтрок - 1, КоличествоКолонок);
Диапазон = Лист.Range(НачальнаяЯчейка, КонечнаяЯчейка);
Диапазон.Value = МассивДанных;
Применение технологии COMSafeArray позволяет выгружать десятки тысяч строк практически мгновенно, нивелируя задержки на сетевое и межпроцессное взаимодействие между 1С и MS Excel.