Чтение файла Excel кодом 1С: COM-объект, диапазоны и типы данных
Содержание
Прочитать таблицу 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 | Нет, но нужен драйвер ACE | Windows, разрядность драйвера = разрядности 1С | Нужно выбрать строки SQL-запросом по листу |
Дальше основная часть — про COM, потому что именно он даёт полный доступ к книге. Безофисный вариант разобран в отдельном разделе.
Если нужна разовая загрузка номенклатуры или строк документа, сначала поищите в типовой конфигурации команду загрузки из файла в командной панели списка или табличной части. В БП 3.0 и УТ 11 она есть у ряда объектов, и писать код не придётся.
Подготовка: где выполнять код и как создать COM-объект Excel
COM-объект Excel создаётся на той машине, где выполняется код. Отсюда два правила:
- 🖥️ Код на клиенте (
&НаКлиенте) — Excel должен стоять у пользователя. Работает в тонком и толстом клиенте под Windows. В веб-клиенте и на LinuxCOMОбъектнедоступен. - 🗄️ Код на сервере (
&НаСервере) — 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)) = "прайс" Тогда
Лист = ТекЛист;
Прервать;
КонецЕсли;
КонецЦикла;
Обращение к несуществующему листу по имени вызывает исключение. Оборачивайте поиск в Попытка … Исключение или перебирайте коллекцию, как в примере выше.
Как узнать, сколько строк заполнено
Есть два надёжных приёма.
- Через
UsedRange— область, которую Excel считает использованной:
ПоследняяСтрока = Лист.UsedRange.Row + Лист.UsedRange.Rows.Count - 1;
ПоследняяКолонка = Лист.UsedRange.Column + Лист.UsedRange.Columns.Count - 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 вернёт само значение, а не массив, и Выгрузить() вызовет ошибку. Для файлов, где может быть одна строка данных, проверяйте размер диапазона заранее.
Ещё несколько настроек, которые заметно экономят время:
Excel.ScreenUpdating = Ложь— Excel не перерисовывает окно.Excel.Calculation = -4135(xlCalculationManual) — книга с формулами не пересчитывается при открытии. Ставьте доWorkbooks.Open, и только если вам нужны уже посчитанные значения.- Поиск ссылок в 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 может вернуть пустоту вместо артикулов-строк в числовой колонке.