При импорте данных из прайс-листов, отчетов или накладных формата Excel часто возникает задача перебрать файлы в каталоге и выгрузить строки с номенклатурой. При этом файл часто имеет переменное количество строк, а внизу таблицы расположен итоговый блок. Разберем, как правильно организовать обход файлов и строк до контрольного слова «Итого».
Рассмотрим типовой код, с которым часто сталкиваются разработчики при написании обработки через COM-объект EXCEL.Application:
Эксель = Новый COMОбъект("EXCEL.Application");
Файлы = НайтиФайлы(ПутьКПапке, "*.xls", Ложь);
Для каждого Файл из Файлы Цикл
Эксель.Workbooks.Open(Файл.ПолноеИмя);
Эксель.Visible = 1;
ТекЛист = Эксель.WorkSheets(1);
Ячейка = 8;
Для Ячейка = 8 по 1000 Цикл // Попытка задать фиксированный или динамический предел
Значение = ТекЛист.Cells(Ячейка, 2).Value;
Сообщить(Значение);
Ячейка = Ячейка + 1; // Ошибка: попытка ручного изменения счетчика в цикле "Для"
КонецЦикла;
Эксель.Workbooks.Close();
КонецЦикла;
В приведенном коде присутствует сразу несколько критических недочетов:
Ячейка = Ячейка + 1 внутри конструкции Для ... По приводит к некорректной работе алгоритма. Для управления итерациями лучше использовать цикл Пока ... КонецЦикла.Workbooks.Close() закрывает книгу, но сам процесс Excel остается висеть в диспетчере задач Windows. Для полного завершения работы необходимо использовать метод Quit() и сбрасывать переменную.Visible = 1 заставляет систему отрисовывать каждый файл на экране, что значительно замедляет работу обработки.Разберем решение задачи с исправленной логикой цикла. Для этого применим цикл Пока, проверку вхождения подстроки через СтрНайти, а также предусмотрим защиту от бесконечного цикла, если ячейка с текстом «Итого» не будет найдена в файле.
Эксель = Новый 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();
Эксель = Неопределено;
Работа через COM-объект имеет существенные ограничения: она работает только в Windows, требует установленного Microsoft Office и выполняется медленно. Платформа 1С позволяет прочитать файлы Excel напрямую с помощью объекта ТабличныйДокумент, что работает как на клиенте, так и на сервере (включая Linux).
Рассмотрим замену COM-автоматизации на штатное чтение файлов:
Файлы = НайтиФайлы(ПутьКПапке, "*.xls", Ложь);
Для каждого Файл из Файлы Цикл
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(Файл.ПолноеИмя, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Не удалось прочитать файл: " + Файл.ПолноеИмя);
Продолжить;
КонецПопытки;
// Ищем ячейку с текстом "Итого" по всей таблице
ОбластьИтого = ТабДок.НайтиТекст("Итого");
Если ОбластьИтого <> Неопределено Тогда
КонечнаяСтрока = ОбластьИтого.Верх - 1; // Читаем до строки с итогом
Иначе
КонечнаяСтрока = ТабДок.ВысотаТаблицы; // Если "Итого" не найдено, читаем до конца
КонецЕсли;
// Перебираем строки от 8 до найденной границы
Для НомерСтроки = 8 По КонечнаяСтрока Цикл
Значение = ТабДок.ПолучитьОбласть(НомерСтроки, 2).ТекущаяОбласть.Текст;
Сообщить("Строка " + НомерСтроки + ": " + Значение);
КонецЦикла;
КонецЦикла;
Преимущества использования ТабличногоДокумента:
НайтиТекст() находит нужную ячейку мгновенно по всему документу без поэлементного перебора всех строк.