Чтение файла Excel кодом 1С: COM-объект, диапазоны и типы данных

· 10 мин

Содержание

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

Типичная ситуация: поставщик прислал прайс на 6 000 строк, а загрузка «по ячейке» идёт полчаса и оставляет в диспетчере задач висящие EXCEL.EXE. Ниже код, который читает такой файл за секунды и не забывает за собой убрать.

Какой способ чтения Excel выбрать в 1С

Перед тем как писать код, решите, где он будет выполняться и есть ли там Excel. От этого зависит способ.

СпособНужен ExcelГде работаетКогда выбирать
COM Excel.ApplicationДаТонкий/толстый клиент под WindowsНужны несколько листов, формулы, видимый текст ячеек
ТабличныйДокумент.Прочитать()НетКлиент и сервер, в том числе LinuxПростая таблица с первого листа, файл xlsx
ADO + Microsoft.ACE.OLEDB.12.0Нет, но нужен драйвер ACEWindows, разрядность драйвера = разрядности 1СНужно выбрать строки SQL-запросом по листу

Дальше основная часть — про COM, потому что именно он даёт полный доступ к книге. Безофисный вариант разобран в отдельном разделе.

Если нужна разовая загрузка номенклатуры или строк документа, сначала поищите в типовой конфигурации команду загрузки из файла в командной панели списка или табличной части. В БП 3.0 и УТ 11 она есть у ряда объектов, и писать код не придётся.

Подготовка: где выполнять код и как создать COM-объект Excel

COM-объект Excel создаётся на той машине, где выполняется код. Отсюда два правила:

  • 🖥️ Код на клиенте (&НаКлиенте) — Excel должен стоять у пользователя. Работает в тонком и толстом клиенте под Windows. В веб-клиенте и на Linux COMОбъект недоступен.
  • 🗄️ Код на сервере (&НаСервере) — Excel должен стоять на сервере 1С и запускаться от имени учётной записи службы (обычно USR1CV8). Microsoft не поддерживает автоматизацию Office из служб, поэтому для серверной загрузки лучше подходит табличный документ.

Создание объекта и базовые настройки:

Excel = Новый COMОбъект("Excel.Application");
Excel.Visible = Ложь;        // не показывать окно
Excel.DisplayAlerts = Ложь;  // не задавать вопросов о сохранении и связях

DisplayAlerts = Ложь обязателен для фоновой работы. Иначе Excel может открыть невидимое окно с вопросом, и код зависнет в ожидании ответа, который никто не даст.

Имя файла на клиенте получают диалогом выбора. В конфигурациях, где синхронные вызовы отключены (так настроены актуальные БП 3.0 и ЗУП 3.1), используйте асинхронный вариант:

&НаКлиенте
Процедура ВыбратьФайл(Команда)
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Книги Excel (*.xlsx;*.xls)|*.xlsx;*.xls";
    Диалог.Показать(Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект));
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    Если ВыбранныеФайлы = Неопределено Тогда
        Возврат;
    КонецЕсли;
    ПрочитатьКнигу(ВыбранныеФайлы[0]);
КонецПроцедуры

Открытие файла Excel и выбор нужного листа

Книгу открывают через коллекцию Workbooks. Третий параметр метода Open — режим «только чтение». Ставьте его всегда: так файл можно прочитать, даже если он открыт у коллеги, и вы точно ничего в нём не испортите.

Книга = Excel.Workbooks.Open(ИмяФайла, 0, Истина);
// 0 — не обновлять внешние связи, Истина — только чтение

Лист берут по номеру или по имени. Нумерация листов в Excel начинается с 1:

Лист = Книга.Worksheets(1);          // первый лист
Лист = Книга.Worksheets("Прайс");    // лист по имени на ярлычке

Если поставщик меняет порядок листов, надёжнее искать по имени. Перебор всех листов книги:

Для Н = 1 По Книга.Worksheets.Count Цикл
    ТекЛист = Книга.Worksheets(Н);
    Если НРег(СокрЛП(ТекЛист.Name)) = "прайс" Тогда
        Лист = ТекЛист;
        Прервать;
    КонецЕсли;
КонецЦикла;

Обращение к несуществующему листу по имени вызывает исключение. Оборачивайте поиск в Попытка … Исключение или перебирайте коллекцию, как в примере выше.

Как узнать, сколько строк заполнено

Есть два надёжных приёма.

  1. Через UsedRange — область, которую Excel считает использованной:
ПоследняяСтрока = Лист.UsedRange.Row + Лист.UsedRange.Rows.Count - 1;
ПоследняяКолонка = Лист.UsedRange.Column + Лист.UsedRange.Columns.Count - 1;
  1. От конца колонки вверх — аналог Ctrl+↑ в Excel. Константа -4162 — это xlUp:
ПоследняяСтрока = Лист.Cells(Лист.Rows.Count, 1).End(-4162).Row;

UsedRange иногда «помнит» строки, из которых данные удалили, но формат остался. Второй способ точнее, если ключевая колонка (например, артикул) заполнена в каждой строке.

Чтение ячеек и диапазонов таблицы Excel

Самый простой вариант — читать ячейку по номеру строки и колонки:

Для Стр = 2 По ПоследняяСтрока Цикл   // строка 1 — шапка
    Артикул = Лист.Cells(Стр, 1).Value;
    Наименование = Лист.Cells(Стр, 2).Value;
    Цена = Лист.Cells(Стр, 3).Value;
КонецЦикла;

У ячейки есть два свойства, которые часто путают:

СвойствоЧто возвращаетПример для ячейки с датой
ValueЗначение с типом: число, строка, датаДата 15.03 нужного года, 0:00:00
TextСтроку ровно так, как её видно на экране"15.03.2026" или "###", если колонка узкая

Text удобен для кодов и артикулов, но зависит от ширины колонки и формата. Если колонка слишком узкая, вместо числа придёт ###. Для сумм и дат берите Value.

Привязка к колонкам по шапке, а не по номерам

Поставщики любят вставлять колонки. Чтобы загрузка не сломалась, найдите номера колонок по тексту шапки один раз перед циклом:

Колонки = Новый Соответствие;
Для Кол = 1 По ПоследняяКолонка Цикл
    Заголовок = НРег(СокрЛП(Лист.Cells(1, Кол).Text));
    Если ЗначениеЗаполнено(Заголовок) Тогда
        Колонки.Вставить(Заголовок, Кол);
    КонецЕсли;
КонецЦикла;

КолАртикул = Колонки.Получить("артикул");
Если КолАртикул = Неопределено Тогда
    ВызватьИсключение "В файле нет колонки «Артикул»";
КонецЕсли;

Объединённые ячейки

В объединённой области значение хранится только в левой верхней ячейке, остальные возвращают пустоту. Если в прайсе группа товаров записана объединённой ячейкой на несколько строк, запоминайте последнее непустое значение и подставляйте его в следующие строки.

Преобразование типов данных и защита от ошибок

COM отдаёт значения в типах Excel, а не в тех, которые ждёт ваш справочник. Главные ловушки:

  • 🔢 Числа строкой. Если в Excel сумма записана как текст "1 250,50", придёт строка с пробелом и запятой. Число() её не примет.
  • 📅 Даты. Через Value настоящая дата придёт как Дата. Но если дату в файле набрали текстом, придёт строка "15.03.2026".
  • 🧾 ИНН, коды, счета. Excel хранит их как числа и теряет ведущие нули: ИНН 0274… превращается в 274…. Кроме того, Excel держит только 15 значащих цифр, поэтому 20-значный номер расчётного счёта, набранный числом, уже испорчен в самом файле.
  • ⬜ Пустые ячейки приходят как Неопределено.

Универсальная функция приведения к числу:

Функция ВЧисло(Значение)
    Если ТипЗнч(Значение) = Тип("Число") Тогда
        Возврат Значение;
    ИначеЕсли Значение = Неопределено Тогда
        Возврат 0;
    КонецЕсли;
    Стр = СокрЛП(Строка(Значение));
    Стр = СтрЗаменить(Стр, Символы.НПП, "");
    Стр = СтрЗаменить(Стр, " ", "");
    Стр = СтрЗаменить(Стр, ",", ".");
    Попытка
        Возврат Число(Стр);
    Исключение
        Возврат 0;
    КонецПопытки;
КонецФункции

И приведения к дате, если в ячейке может оказаться и дата, и текст формата ДД.ММ.ГГГГ:

Функция ВДату(Значение)
    Если ТипЗнч(Значение) = Тип("Дата") Тогда
        Возврат Значение;
    ИначеЕсли ТипЗнч(Значение) = Тип("Строка") И СтрДлина(СокрЛП(Значение)) = 10 Тогда
        Стр = СокрЛП(Значение);
        Попытка
            Возврат Дата(Прав(Стр, 4) + Сред(Стр, 4, 2) + Лев(Стр, 2));
        Исключение
            Возврат '00010101';
        КонецПопытки;
    КонецЕсли;
    Возврат '00010101';
КонецФункции

Для ИНН и кодов берите Text, а если пришло число — форматируйте без разделителей групп: Формат(Значение, "ЧГ=0"). Ведущий ноль так не вернётся, поэтому строку с ИНН короче 10 символов лучше вывести в протокол ошибок, а не загружать молча.

Не прерывайте всю загрузку из-за одной кривой строки. Собирайте ошибки в массив вида «строка 418: не распознана цена» и показывайте их в конце. Пользователь исправит файл и загрузит снова.

Как ускорить чтение большой таблицы Excel

Каждое обращение Лист.Cells(Стр, Кол).Value — отдельный вызов между процессами 1С и Excel. На прайсе в 10 000 строк и 8 колонок это 80 000 вызовов, отсюда минуты ожидания.

Главный приём — забрать весь диапазон одним вызовом. Свойство Value у диапазона возвращает объект COMSafeArray, а его метод Выгрузить() превращает данные в обычный массив 1С:

Область = Лист.Range(Лист.Cells(1, 1), Лист.Cells(ПоследняяСтрока, ПоследняяКолонка));
Данные = Область.Value.Выгрузить();

// первый индекс — колонка, второй — строка, нумерация с нуля
Для Стр = 1 По ПоследняяСтрока - 1 Цикл     // индекс 0 — шапка
    Артикул = Данные[КолАртикул - 1][Стр];
    Цена = ВЧисло(Данные[КолЦена - 1][Стр]);
КонецЦикла;

Порядок индексов здесь «перевёрнут» относительно привычного Excel: сначала колонка, потом строка. Проверить легко: на файле из 3 колонок и 100 строк Данные.Количество() вернёт 3.

Если диапазон состоит из одной ячейки, Value вернёт само значение, а не массив, и Выгрузить() вызовет ошибку. Для файлов, где может быть одна строка данных, проверяйте размер диапазона заранее.

Ещё несколько настроек, которые заметно экономят время:

  1. Excel.ScreenUpdating = Ложь — Excel не перерисовывает окно.
  2. Excel.Calculation = -4135 (xlCalculationManual) — книга с формулами не пересчитывается при открытии. Ставьте до Workbooks.Open, и только если вам нужны уже посчитанные значения.
  3. Поиск ссылок в 1С делайте не в цикле по строкам, а одним запросом. Соберите все артикулы в таблицу значений, передайте её в запрос как параметр и получите соответствие «артикул → номенклатура» за один проход.

Последний пункт часто даёт больший выигрыш, чем все настройки Excel: 6 000 вызовов НайтиПоРеквизиту на сервере работают медленнее одного запроса с временной таблицей.

Закрытие Excel и освобождение ресурсов

Самая частая жалоба после первой загрузки — в диспетчере задач копятся процессы EXCEL.EXE. Причина одна: код завершился с ошибкой до вызова Quit() или в переменных остались ссылки на COM-объекты.

Правильный каркас с гарантированным закрытием:

&НаКлиенте
Процедура ПрочитатьКнигу(ИмяФайла)
    Excel = Неопределено;
    Книга = Неопределено;
    Лист = Неопределено;
    ТекстОшибки = "";

    Попытка
        Excel = Новый COMОбъект("Excel.Application");
        Excel.Visible = Ложь;
        Excel.DisplayAlerts = Ложь;
        Книга = Excel.Workbooks.Open(ИмяФайла, 0, Истина);
        Лист = Книга.Worksheets(1);
        // ... чтение данных ...
    Исключение
        ТекстОшибки = ОписаниеОшибки();
    КонецПопытки;

    Попытка
        Если Книга <> Неопределено Тогда
            Книга.Close(Ложь);   // закрыть без сохранения
        КонецЕсли;
        Если Excel <> Неопределено Тогда
            Excel.Quit();
        КонецЕсли;
    Исключение
        // Excel уже закрыт или недоступен
    КонецПопытки;

    Лист = Неопределено;
    Книга = Неопределено;
    Excel = Неопределено;

    Если ЗначениеЗаполнено(ТекстОшибки) Тогда
        Сообщить("Не удалось прочитать файл: " + ТекстОшибки);
    КонецЕсли;
КонецПроцедуры

Обнулять нужно все переменные, где лежали COM-объекты: лист, диапазон, книгу и само приложение. Пока на объект есть ссылка, процесс Excel может не выгрузиться даже после Quit().

Если зависшие EXCEL.EXE уже есть, перед их завершением в диспетчере задач убедитесь, что у пользователя нет открытых рабочих книг: снимается весь процесс, и несохранённые изменения в его файлах Excel пропадут.

Чтение Excel без установленного Office

Если Excel нет на компьютере или загрузка должна работать на сервере, используйте табличный документ. Метод Прочитать() открывает файл xlsx и ods средствами самой платформы, без Office. Нужна платформа с номером не ниже 8.3.6.

Схема для управляемой формы: клиент помещает файл во временное хранилище, сервер записывает его во временный файл и читает:

&НаСервере
Процедура ПрочитатьНаСервере(АдресФайла)
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
    ДвоичныеДанные.Записать(ИмяВременногоФайла);

    ТабДок = Новый ТабличныйДокумент;
    ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    УдалитьФайлы(ИмяВременногоФайла);

    Для Стр = 2 По ТабДок.ВысотаТаблицы Цикл
        Артикул = СокрЛП(ТабДок.Область(Стр, 1, Стр, 1).Текст);
        Цена = ВЧисло(ТабДок.Область(Стр, 3, Стр, 3).Текст);
        // ...
    КонецЦикла;
КонецПроцедуры

Ограничения табличного документа:

  • 📄 читается первый лист книги, остальные придётся сохранить отдельными файлами;
  • 🧮 формулы не пересчитываются, приходит сохранённый в файле результат;
  • 🔤 значения удобнее брать через Текст и приводить функциями из раздела про типы.

Третий вариант — ADO. Файл открывают как базу данных строкой подключения Provider=Microsoft.ACE.OLEDB.12.0;Data Source=<путь>;Extended Properties="Excel 12.0 Xml;HDR=YES;IMEX=1" и читают запросом SELECT * FROM [Лист1$]. Драйвер ACE ставится отдельно, и его разрядность должна совпадать с разрядностью клиента или сервера 1С. Параметр IMEX=1 заставляет читать колонки со смешанными данными как текст — без него ADO может вернуть пустоту вместо артикулов-строк в числовой колонке.

Ошибки при чтении Excel в 1С и что с ними делать

Диагностика: выберите симптом