Где и как быстрее обрабатывать файлы Excel в 1С: на клиенте или на сервере?

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

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

1. Выбор контекста: Клиент или Сервер

Выбор места выполнения зависит от режима работы информационной базы и используемых методов чтения:

  1. Файловый режим работы: В файловой базе и клиент, и сервер фактически выполняются на одном физическом компьютере. Однако контекст &НаСервере все равно изолирован. Передача больших коллекций (например, промежуточных таблиц) между клиентом и сервером требует времени на сериализацию данных во временное хранилище или реквизиты формы.
  2. Клиент-серверный режим: Если чтение файла выполняется на клиенте, файл не передается по сети целиком на сервер приложения, а ресурсы сервера остаются свободными для других пользователей и регламентных задач. Если чтение выполняется на сервере, файл предварительно необходимо передать через ПоместитьВоВременноеХранилище(), но серверные мощности обычно выше клиентских рабочих станций.
  3. Ограничения типов данных: Объект ТаблицаЗначений недоступен в тонком клиенте. Если чтение выполняется на клиенте, данные приходится считывать в массивы или структуры, либо использовать универсальные коллекции формы (ДанныеФормыКоллекция), что увеличивает расход памяти.

2. Способ 1: Нативное чтение через ТабличныйДокумент

Самый простой и кроссплатформенный вариант чтения файлов форматов .xls и .xlsx — использование встроенного объекта ТабличныйДокумент. Он работает как на клиенте, так и на сервере без необходимости установки сторонних программных пакетов.

Разберем по шагам, как прочитать файл и преобразовать его строки в коллекцию:


&НаСервере
Функция ПрочитатьФайлЧерезТабДок(АдресФайла)
    ТабДок = Новый ТабличныйДокумент;
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
    ДвоичныеДанные.Записать(ИмяВременногоФайла);
    
    ТабДок.Прочитать(ИмяВременногоФайла);
    УдалитьФайлы(ИмяВременногоФайла);
    
    ТаблицаРезультат = Новый ТаблицаЗначений;
    ТаблицаРезультат.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(50)));
    ТаблицаРезультат.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
    
    ВсегоСтрок = ТабДок.ВысотаТаблицы;
    Для НомерСтроки = 2 По ВсегоСтрок Цикл
        НоваяСтрока = ТаблицаРезультат.Добавить();
        НоваяСтрока.Артикул = СокрЛП(ТабДок.ПолучитьОбласть(НомерСтроки, 1).Текст);
        НоваяСтрока.Количество = Число(ТабДок.ПолучитьОбласть(НомерСтроки, 2).Текст);
    КонецЦикла;
    
    Возврат ТаблицаРезультат;
КонецФункции

3. Способ 2: Оптимизированная работа через COM-объект Excel.Application

При использовании COM-соединения частой ошибкой является поячеечный обход таблицы через Лист.Cells(Строка, Колонка).Value. Это приводит к тысячам межпроцессных вызовов и критически замедляет работу. Чтобы ускорить загрузку, следует считывать всю используемую область таблицы в двумерный COM-массив за одно обращение.

Посмотрим на пример выгрузки данных через свойство UsedRange:


&НаКлиенте
Процедура ЗагрузитьЧерезCOM(ПутьКФайлу)
    Попытка
        ExcelПриложение = Новый COMОбъект("Excel.Application");
        ExcelПриложение.Visible = Ложь;
        ExcelПриложение.DisplayAlerts = Ложь;
        
        Книга = ExcelПриложение.Workbooks.Open(ПутьКФайлу);
        Лист = Книга.Sheets(1);
        
        // Считываем весь диапазон в память одним вызовом
        МассивДанных = Лист.UsedRange.Value;
        
        Книга.Close(Ложь);
        ExcelПриложение.Quit();
    Исключение
        Если ExcelПриложение <> Неопределено Тогда
            ExcelПриложение.Quit();
        КонецЕсли;
        ВызватьИсключение;
    КонецПопытки;
    
    // Обязательно очищаем ссылки для завершения процесса EXCEL.EXE
    Лист = Неопределено;
    Книга = Неопределено;
    ExcelПриложение = Неопределено;
    
    // Обработка SafeArray в 1С
    КоличествоСтрок = МассивДанных.UBound(1);
    Для НомерСтроки = 2 По КоличествоСтрок Цикл
        ЗначениеКолонки1 = МассивДанных.GetValue(1, НомерСтроки);
        ЗначениеКолонки2 = МассивДанных.GetValue(2, НомерСтроки);
    КонецЦикла;
КонецПроцедуры

4. Способ 3: Разбор структуры XLSX через ЧтениеZipФайла и ЧтениеXML

Для достижения максимальной скорости чтения больших файлов .xlsx на сервере без применения COM-объектов используют прямой потоковый разбор XML-структуры архива:

  1. Файл .xlsx распаковывается с помощью объекта ЧтениеZipФайла во временный каталог.
  2. С помощью ЧтениеXML считывается файл сопоставления строковых значений sharedStrings.xml в массив.
  3. Последовательно разбирается файл листа sheet1.xml, где номера ячеек подставляются в результирующую структуру.

Этот метод не блокирует память целиком под всю таблицу и работает в десятки раз быстрее, чем COM-соединение.

5. Оптимизация сопоставления двух наборов данных

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

  1. Индексация ТаблицыЗначений: При поиске через НайтиСтроки() обязательно добавьте индекс: ТаблицаДанных.Индексы.Добавить("КодСопоставления"); Это переводит алгоритм поиска из полного перебора в логарифмический поиск по индексному дереву.
  2. Использование запросов и временных таблиц: Загрузите обе таблицы в МенеджерВременныхТаблиц и выполните сопоставление через оператор ПОЛНОЕ СОЕДИНЕНИЕ или ЛЕВОЕ СОЕДИНЕНИЕ средствами СУБД. Это минимизирует код и ускоряет вычисления.

6. Индикация прогресса выполнения

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

← На главную