Многие разработчики сталкиваются с тем, что после обновления платформы 1С:Предприятие (например, до версии 8.3.20 и выше) загрузка объемных данных из файлов Excel начинает работать катастрофически медленно. Процесс, который ранее занимал приемлемое время, может растянуться на много часов. Давайте проанализируем ситуацию, выясним причину такого поведения платформы и разберем по шагам, как кардинально ускорить получение данных из таблиц.
Обычно в устаревшем коде загрузки используется построчный перебор ячеек в цикле, где данные читаются конструкцией вида Лист.Cells(Строка, Колонка).Value. Проблема заключается в том, что при каждом таком вызове 1С совершает отдельное обращение через границу процессов к приложению MS Excel.
В новых версиях платформы 1С и новых версиях операционных систем Windows механизмы безопасности и внутренней архитектуры изменились, из-за чего кросс-процессные COM-вызовы стали обходиться операционной системе намного "дороже" по времени. Если в файле десятки тысяч строк и множество колонок, 1С выполняет миллионы независимых обращений к Excel, что и приводит к зависаниям на несколько часов.
Рассмотрим подробнее самый правильный и быстрый подход при работе через COM-соединение. Чтобы избавиться от архитектурной проблемы медленного соединения, нам нужно сделать всего одно обращение к Excel, забрать сразу все данные и затем обрабатывать их уже внутри оперативной памяти 1С.
Для этого мы обратимся к свойству Value у объекта Range. В этом случае Excel сформирует и вернет специальный объект COMSafeArray. В свою очередь, платформа 1С умеет мгновенно конвертировать его в привычный многомерный массив с помощью встроенного метода Выгрузить().
Посмотрим на пример кода, который позволил сократить время чтения с 7 часов до 11 минут:
КоличествоЛистов = Книга.Sheets.Count;
Лист = Книга.Sheets(1);
// Получаем границы заполненных данных
ВсегоКолонок = Лист.Cells(1,1).SpecialCells(11).Column;
ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row;
// Выделяем всю заполненную область
Область = Лист.Range(Лист.Cells(1,1), Лист.Cells(ВсегоСтрок, ВсегоКолонок));
// Совершаем одно обращение к Excel и выгружаем данные в многомерный массив 1С
Данные = Область.Value.Выгрузить();
// Теперь переменная "Данные" содержит двумерный массив 1С
// Перебор массива работает моментально:
Для ИндексСтроки = 0 По Данные.ВГраница() Цикл
// Читаем значения массива
КоличествоПродНЕОБР = Данные[ИндексСтроки][КолонкаКоличествоПродажа];
// ... дальнейшая логика
КонецЦикла;
При таком подходе мы полностью исключаем постоянные дерганья Excel в цикле, и все вычисления происходят исключительно на стороне 1С.
Другим классическим способом ускорения является чтение файла средствами Microsoft ADO. Этот метод рассматривает файл Excel как базу данных и позволяет обращаться к листам с помощью SQL-запросов.
Однако при использовании драйверов ADODB необходимо учитывать подводные камни:
Null, посчитав текст ошибкой формата.GetRows() для получения массива записей, вместо перебора объекта Recordset в цикле.Часто разработчики пытаются уйти от COM-объектов, используя штатный метод платформы ТабличныйДокумент.Прочитать(ПутьКФайлу). Но если затем обходить документ циклами ТабДок.Область(R, C).Текст, это тоже работает недостаточно быстро.
Разберем обходной маневр, который позволяет быстро преобразовать прочитанный табличный документ в удобную для работы таблицу значений без циклов:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);
Построитель = Новый ПостроительЗапроса;
// Передаем область загруженного документа в качестве источника данных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДок.Область());
Построитель.Выполнить();
// Выгружаем результат напрямую в Таблицу Значений
ТаблицаИзExcel = Построитель.Результат.Выгрузить();
Этот метод работает исключительно силами платформы 1С, не требует установки MS Office на сервере и отлично подходит для кроссплатформенных сред (например, при работе серверов 1С на ОС Linux).
Самым современным подходом, который сейчас активно внедряется в типовых конфигурациях 1С, является полный отказ от внешних приложений (COM) и драйверов. Дело в том, что файлы формата .xlsx представляют собой обычные ZIP-архивы, внутри которых структура документа описана в виде XML-файлов.
Нативное чтение подразумевает распаковку этого архива средствами 1С (объект ЧтениеZipФайла) и прямой парсинг XML (с помощью ЧтениеXML или ПостроительDOM).
Это самый отказоустойчивый метод для загрузки гигантских прайс-листов. Он полностью страхует систему от ситуаций, когда на сервере зависают невидимые фоновые экземпляры Excel.Application, которые постепенно съедают всю оперативную память.
Подведем итог: если вам необходимо быстро оптимизировать старую обработку загрузки, работающую через COM, используйте чтение всего листа в COMSafeArray. Если же вы разрабатываете новый надежный функционал обмена для высоконагруженной базы — отдавайте предпочтение чтению через табличный документ или нативному разбору XML-структуры XLSX-файла.