Как прочитать Excel файл, если данные начинаются с произвольной строки?

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

В практике интеграции 1С с внешними системами часто встречается задача загрузки данных из Excel-файлов, структура которых не является строго фиксированной. Проблема заключается в том, что полезные данные могут начинаться как с 1-й, так и с 100-й строки. Файл может содержать пустые строки в начале, декоративные заголовки, «мусорную» информацию или объединенные ячейки, которые мешают корректному определению состава колонок. Разберем наиболее эффективные способы решения этой задачи, проанализируем подходы к оптимизации и выясним, как правильно обрабатывать сложные структуры данных.

Метод 1: Предварительный поиск строки-маркера через COM-объект

Рассмотрим ситуацию, когда мы заранее не знаем номер строки, но знаем «ключевое слово» (например, «Артикул», «Номенклатура» или «Количество»), которое гарантированно присутствует в шапке таблицы. Самый простой, хотя и не самый быстрый способ — это перебор строк в цикле до момента нахождения нужного значения.

Проанализируем пример кода, предложенный в обсуждении, и немного доработаем его для универсальности:


// Инициализация Excel
Excel = Новый COMОбъект("Excel.Application");
Книга = Excel.Workbooks.Open(ПутьКФайлу);
Лист = Книга.Sheets(1);

// Определяем общее количество строк
ВсегоСтрок = Лист.Cells.SpecialCells(11).Row;
НомерСтартовойСтроки = 0;
ИмяКолонкиДляПоиска = "Артикул";

// Цикл поиска заголовка
Для НомерСтроки = 1 По ВсегоСтрок Цикл
    ЗначениеЯчейки = СокрЛП(Лист.Cells(НомерСтроки, 1).Value); // Ищем в первой колонке
    Если Найти(ЗначениеЯчейки, ИмяКолонкиДляПоиска) > 0 Тогда
        НомерСтартовойСтроки = НомерСтроки + 1; // Данные начинаются со следующей строки
        Прервать;
    КонецЕсли;
КонецЦикла;

Если НомерСтартовойСтроки > 0 Тогда
    // Дальнейшая логика чтения данных начиная с НомерСтартовойСтроки
КонецЕсли;

Важный нюанс: Обращение к каждой ячейке через Cells(i, j).Value в цикле — это очень медленная операция, так как каждый вызов проходит через COM-интерфейс. Если в файле тысячи строк, такой поиск может занять значительное время.

Метод 2: Оптимизированное чтение через массив (SafeArray)

Для ускорения работы с COM-объектом Excel рекомендуется использовать выгрузку всего диапазона данных в массив 1С за один вызов. Это позволяет мгновенно получить доступ ко всем данным в оперативной памяти.

Рассмотрим, как это реализовать:


// Получаем сразу все данные листа в массив
МассивДанных = Лист.UsedRange.Value.Выгрузить();

// Теперь работаем с обычным массивом 1С, что в десятки раз быстрее
Для НомерСтроки = 0 По МассивДанных.ВГраница() Цикл
    // В массиве индексы колонок тоже начинаются с 0
    Если ЗначениеЗаполнено(МассивДанных[НомерСтроки][0]) Тогда 
        // Здесь проверяем условие начала данных
        // ...
    КонецЕсли;
КонецЦикла;

Этот подход позволяет избежать «тормозов» при чтении больших файлов и значительно стабильнее работает при поиске нужной строки.

Метод 3: Использование Табличного документа (без установки Excel)

Если на сервере или компьютере пользователя не установлен Microsoft Office, или если требуется максимальная скорость и стабильность, следует использовать встроенный объект 1С ТабличныйДокумент. Метод Прочитать() работает нативно и корректно распознает форматы .xls и .xlsx.

Разберем алгоритм поиска нужной строки в ТабличныйДокумент:

  1. Создаем новый объект ТабличныйДокумент.
  2. Читаем файл методом Прочитать(ПутьКФайлу).
  3. Используем метод НайтиТекст() для быстрого позиционирования.

ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);

// Ищем ячейку с заголовком "Номенклатура"
ОбластьЗаголовка = ТабДок.НайтиТекст("Номенклатура");

Если ОбластьЗаголовка <> Неопределено Тогда
    НомерСтартовойСтроки = ОбластьЗаголовка.Верх;
    // Начинаем чтение данных со строки НомерСтартовойСтроки + 1
Иначе
    Сообщить("Заголовок не найден!");
КонецЕсли;

Преимущество этого метода в том, что ТабличныйДокумент автоматически обрабатывает объединенные ячейки. При чтении значения из объединения, 1С вернет данные для левой верхней ячейки области, что позволяет легко идентифицировать начало таблицы, даже если заголовок «размазан» по нескольким ячейкам.

Обработка объединенных ячеек

Проанализируем ситуацию, упомянутую в сообщении №2 форума: когда в начале файла есть объединенные ячейки, они могут «сбивать» структуру колонок при чтении через определенные драйверы. Однако при использовании ТабличныйДокумент или COM-объекта Excel.Application, мы можем программно проверить, является ли ячейка частью объединения.

В COM-объекте это проверяется через свойство MergeCells. Если оно истинно, можно получить всю область через MergeArea:


Если Лист.Cells(НомерСтроки, НомерКолонки).MergeCells Тогда
    КоличествоСтрокВОбъединении = Лист.Cells(НомерСтроки, НомерКолонки).MergeArea.Rows.Count;
    // Это поможет понять, сколько строк нужно пропустить или учесть как единый заголовок
КонецЕсли;

Как найти «реальный» конец данных?

Часто проблема заключается не только в начале, но и в определении конца данных. Свойство UsedRange в Excel часто возвращает диапазон, включающий ячейки, которые когда-то редактировались, но сейчас пусты. Чтобы найти действительно последнюю заполненную строку, мы можем использовать цикл с конца таблицы вверх до первой заполненной ячейки:


ПоследняяСтрока = Лист.Cells.SpecialCells(11).Row;
Пока ПоследняяСтрока > 0 Цикл
    Если ЗначениеЗаполнено(Лист.Cells(ПоследняяСтрока, 1).Value) Тогда
        Прервать;
    КонецЕсли;
    ПоследняяСтрока = ПоследняяСтрока - 1;
КонецЦикла;

Выводы и рекомендации

Для надежного чтения Excel с «плавающим» началом данных мы рекомендуем придерживаться следующей стратегии:

Таким образом, комбинируя методы поиска текста и эффективные способы извлечения данных, можно создать универсальный загрузчик, устойчивый к изменениям в структуре входящих Excel-файлов.

← На главную