Как в 1С пройти циклом по файлам Excel и обработать строки до ячейки со значением «Итого»?

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

При импорте данных из прайс-листов, отчетов или накладных формата Excel часто возникает задача перебрать файлы в каталоге и выгрузить строки с номенклатурой. При этом файл часто имеет переменное количество строк, а внизу таблицы расположен итоговый блок. Разберем, как правильно организовать обход файлов и строк до контрольного слова «Итого».

Анализ частых ошибок при реализации цикла

Рассмотрим типовой код, с которым часто сталкиваются разработчики при написании обработки через COM-объект EXCEL.Application:


Эксель = Новый COMОбъект("EXCEL.Application");
Файлы = НайтиФайлы(ПутьКПапке, "*.xls", Ложь);

Для каждого Файл из Файлы Цикл
    Эксель.Workbooks.Open(Файл.ПолноеИмя);
    Эксель.Visible = 1;
    ТекЛист = Эксель.WorkSheets(1);
    
    Ячейка = 8;
    Для Ячейка = 8 по 1000 Цикл // Попытка задать фиксированный или динамический предел
        Значение = ТекЛист.Cells(Ячейка, 2).Value;
        Сообщить(Значение);
        Ячейка = Ячейка + 1; // Ошибка: попытка ручного изменения счетчика в цикле "Для"
    КонецЦикла;
    
    Эксель.Workbooks.Close();
КонецЦикла;

В приведенном коде присутствует сразу несколько критических недочетов:

  1. Принудительное изменение счетчика: Изменение переменной цикла Ячейка = Ячейка + 1 внутри конструкции Для ... По приводит к некорректной работе алгоритма. Для управления итерациями лучше использовать цикл Пока ... КонецЦикла.
  2. Зависание процессов в памяти: Метод Workbooks.Close() закрывает книгу, но сам процесс Excel остается висеть в диспетчере задач Windows. Для полного завершения работы необходимо использовать метод Quit() и сбрасывать переменную.
  3. Низкая скорость работы: Установка свойства Visible = 1 заставляет систему отрисовывать каждый файл на экране, что значительно замедляет работу обработки.

Вариант 1. Использование цикла «Пока» с COM-объектом

Разберем решение задачи с исправленной логикой цикла. Для этого применим цикл Пока, проверку вхождения подстроки через СтрНайти, а также предусмотрим защиту от бесконечного цикла, если ячейка с текстом «Итого» не будет найдена в файле.


Эксель = Новый COMОбъект("EXCEL.Application");
Эксель.Visible = 0; // Отключаем видимость для ускорения
Эксель.DisplayAlerts = 0; // Отключаем предупреждения Excel

Файлы = НайтиФайлы(ПутьКПапке, "*.xls", Ложь);

Для каждого Файл из Файлы Цикл
    Книга = Эксель.Workbooks.Open(Файл.ПолноеИмя);
    ТекЛист = Книга.WorkSheets(1);
    
    НомерСтроки = 8;
    ПозИтог = 0;
    
    // Выполняем цикл, пока не найдем "Итого" или не достигнем лимита строк
    Пока ПозИтог = 0 И НомерСтроки < 5000 Цикл
        Значение = ТекЛист.Cells(НомерСтроки, 2).Value;
        
        // Проверяем текстовое значение ячейки
        ТекстЯчейки = СокрЛП(Строка(Значение));
        ПозИтог = СтрНайти(ТекстЯчейки, "Итого");
        
        Если ПозИтог = 0 Тогда
            // Обрабатываем данные строки
            Сообщить("Строка " + НомерСтроки + ": " + ТекстЯчейки);
            НомерСтроки = НомерСтроки + 1;
        КонецЕсли;
    КонецЦикла;
    
    Книга.Close(Ложь); // Закрываем файл без сохранения изменений
КонецЦикла;

// Корректно завершаем работу Excel и освобождаем память
Эксель.Quit();
Эксель = Неопределено;

Вариант 2. Оптимальный способ через «ТабличныйДокумент» (Без COM)

Работа через COM-объект имеет существенные ограничения: она работает только в Windows, требует установленного Microsoft Office и выполняется медленно. Платформа 1С позволяет прочитать файлы Excel напрямую с помощью объекта ТабличныйДокумент, что работает как на клиенте, так и на сервере (включая Linux).

Рассмотрим замену COM-автоматизации на штатное чтение файлов:


Файлы = НайтиФайлы(ПутьКПапке, "*.xls", Ложь);

Для каждого Файл из Файлы Цикл
    ТабДок = Новый ТабличныйДокумент;
    
    Попытка
        ТабДок.Прочитать(Файл.ПолноеИмя, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    Исключение
        Сообщить("Не удалось прочитать файл: " + Файл.ПолноеИмя);
        Продолжить;
    КонецПопытки;
    
    // Ищем ячейку с текстом "Итого" по всей таблице
    ОбластьИтого = ТабДок.НайтиТекст("Итого");
    
    Если ОбластьИтого <> Неопределено Тогда
        КонечнаяСтрока = ОбластьИтого.Верх - 1; // Читаем до строки с итогом
    Иначе
        КонечнаяСтрока = ТабДок.ВысотаТаблицы; // Если "Итого" не найдено, читаем до конца
    КонецЕсли;
    
    // Перебираем строки от 8 до найденной границы
    Для НомерСтроки = 8 По КонечнаяСтрока Цикл
        Значение = ТабДок.ПолучитьОбласть(НомерСтроки, 2).ТекущаяОбласть.Текст;
        Сообщить("Строка " + НомерСтроки + ": " + Значение);
    КонецЦикла;
КонецЦикла;

Преимущества использования ТабличногоДокумента:

← На главную