Чтение Excel-файла программно в 1С 8.3: табличный документ, COM и ADO
Содержание
Прочитать данные из Excel в 1С 8.3 проще всего методом ТабличныйДокумент.Прочитать(ИмяФайла): платформа сама открывает xlsx, а ячейки вы забираете через ТабДок.Область(Строка, Колонка).Текст. Excel на компьютере для этого не нужен. Второй путь — COM-объект Excel.Application, он работает только в Windows и только там, где установлен Microsoft Excel.
Код одинаков для БП 3.0, ЗУП 3.1, УТ 11 и самописных конфигураций: всё описанное относится к платформе 1С:Предприятие 8.3 и управляемым формам.
С чего начать: где лежит файл и чем его открывать
Перед первой строкой кода ответьте на три вопроса. От них зависит выбор технологии.
- 📁 Где файл. На компьютере пользователя, в сетевой папке или уже на сервере 1С. В клиент-серверной базе код сервера не видит диск пользователя.
- 🖥️ Где выполняется чтение. На клиенте, на сервере 1С под Windows или под Linux. На Linux COM нет вообще.
- 📊 Какой объём. Сто строк прочитает любой способ. Пятьдесят тысяч строк через ячейки COM будут читаться минутами.
Быстрый выбор:
| Ситуация | Что использовать |
|---|---|
| Обычный xlsx, любой сервер, Excel не установлен | ТабличныйДокумент.Прочитать |
| Нужны формулы, скрытые листы, формат ячеек | COM Excel.Application |
| Сервер на Linux | Только табличный документ |
| Старая база на обычных формах, Excel у всех стоит | COM на клиенте |
| Файл в десятки тысяч строк | Табличный документ или COM с чтением диапазона целиком |
Если задача разовая — загрузить номенклатуру или остатки, — сначала посмотрите стандартную загрузку из файла. В типовых конфигурациях на БСП в списках справочников и в табличных частях документов есть команда загрузки из файла с сопоставлением колонок. Код писать не придётся.
Способ 1. Табличный документ: чтение xlsx без Microsoft Excel
Метод Прочитать у объекта ТабличныйДокумент разбирает файл средствами платформы. Он одинаково работает на клиенте и на сервере, под Windows и Linux. Уверенно поддерживаются форматы xlsx и ods; поддержку старого xls проверьте на своей версии платформы.
Минимальный код на сервере
&НаСервереБезКонтекста
Функция ПрочитатьExcel(ИмяФайла)
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Результат = Новый Массив;
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл // 1-я строка — шапка
Артикул = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
Если ПустаяСтрока(Артикул) Тогда
Продолжить;
КонецЕсли;
Строка = Новый Структура;
Строка.Вставить("Артикул", Артикул);
Строка.Вставить("Наименование", СокрЛП(ТабДок.Область(НомерСтроки, 2).Текст));
Строка.Вставить("Количество", ТабДок.Область(НомерСтроки, 3).Текст);
Результат.Добавить(Строка);
КонецЦикла;
Возврат Результат;
КонецФункции
Что здесь важно:
ВысотаТаблицыиШиринаТаблицы— число строк и колонок с данными. Цикл по ним не выходит за пределы заполненной области.Область(Строка, Колонка)возвращает одну ячейку. Номера начинаются с единицы, как в Excel.- Второй параметр
Прочитать— способ чтения значений. С вариантомЗначениеплатформа берёт значения ячеек, а не их отображение. Без параметра, или со способомТекст, вы получите то, что видно на экране: число 1 234,50 может прийти строкой с пробелом-разделителем.
Читать только первый лист
Табличный документ читает из xlsx первый лист книги. Если данные на втором листе, попросите пользователя переложить их на первый или используйте COM, где лист выбирают по имени.
Табличный документ → таблица значений одной командой
Когда в первой строке файла аккуратная шапка, обходить ячейки вручную не нужно. Построитель запроса превращает область табличного документа в таблицу значений, а заголовки колонок становятся именами колонок:
Область = ТабДок.Область(1, 1, ТабДок.ВысотаТаблицы, ТабДок.ШиринаТаблицы);
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(Область);
Построитель.Выполнить();
ТаблицаДанных = Построитель.Результат.Выгрузить();
Дальше с ТаблицаДанных работают как с любой таблицей значений: НайтиСтроки, Свернуть, передача в запрос как временная таблица.
Заголовки в шапке должны быть допустимыми именами: без пробелов в начале, без точек и скобок, не начинаться с цифры. Иначе построитель переименует колонку или выдаст ошибку. Надёжнее заранее договориться о шапке вида Артикул | Наименование | Количество.
Способ 2. COM-объект Excel.Application
COM-подключение запускает настоящий Excel в фоне и управляет им из 1С. Вы получаете всё, что умеет Excel: любой лист, формулы, объединённые ячейки, формат. Цена — зависимость от установленного Excel и скорость.
Рабочий пример с закрытием Excel
Процедура ПрочитатьЧерезCOM(ИмяФайла)
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
ВызватьИсключение "Не удалось запустить Microsoft Excel: " + ОписаниеОшибки();
КонецПопытки;
Excel.DisplayAlerts = Ложь;
Excel.Visible = Ложь;
Попытка
Книга = Excel.Workbooks.Open(ИмяФайла);
Лист = Книга.Sheets(1); // или Книга.Sheets("Остатки")
ПоследняяСтрока = Лист.UsedRange.Rows.Count;
Для НомерСтроки = 2 По ПоследняяСтрока Цикл
Артикул = Лист.Cells(НомерСтроки, 1).Value;
Количество = Лист.Cells(НомерСтроки, 3).Value;
// обработка строки
КонецЦикла;
Книга.Close(Ложь);
Исключение
Excel.Quit();
ВызватьИсключение ОписаниеОшибки();
КонецПопытки;
Excel.Quit();
Excel = Неопределено;
КонецПроцедуры
Три момента, на которых чаще всего спотыкаются:
- Путь к файлу — полный.
Workbooks.Openне знает текущий каталог 1С. Передавайте путь видаC:\Обмен\остатки.xlsx. Excel.Quit()в любом исходе. Если код упал междуOpenиQuit, процессEXCEL.EXEостаётся висеть в памяти и держит файл. ПоэтомуQuitстоит и в ветке исключения.UsedRangeначинается не всегда с A1. Если первые строки листа пустые,UsedRange.Rows.Countдаст меньшее число, чем номер последней строки. Для надёжности считайте последнюю строку какЛист.UsedRange.Row + Лист.UsedRange.Rows.Count - 1.
Типы значений из COM
Cells(...).Value возвращает значение с типом Excel. Числа приходят числами, текст — строкой, пустая ячейка — Неопределено. Дата обычно приходит датой, но если в ячейке дата записана текстом, вы получите строку. Это нужно учитывать при проверке, о ней ниже.
COM на сервере 1С
Технически Новый COMОбъект("Excel.Application") работает и в серверном коде, если сервер на Windows и на нём установлен Excel. На практике это источник проблем: Excel запускается под учётной записью службы 1С, может зависнуть на скрытом диалоге и не предназначен для серверной автоматизации. Для серверной загрузки берите табличный документ.
Как передать файл пользователя на сервер
В клиент-серверной базе путь C:\Users\buh\Desktop\прайс.xlsx существует только на компьютере бухгалтера. Сервер 1С его не откроет. Файл нужно сначала поместить во временное хранилище, а на сервере записать во временный файл.
Клиентская часть с выбором файла:
&НаКлиенте
Процедура ЗагрузитьИзExcel(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат; // пользователь закрыл диалог
КонецЕсли;
ЗагрузитьНаСервере(Адрес);
КонецПроцедуры
Серверная часть:
&НаСервере
Процедура ЗагрузитьНаСервере(Адрес)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
УдалитьФайлы(ИмяВременногоФайла);
// разбор ТабДок, как в способе 1
КонецПроцедуры
Удаляйте временный файл сразу после чтения. Каталог временных файлов сервера 1С иначе постепенно зарастает копиями прайсов и выгрузок.
Табличный документ, COM или ADO: сравнение
Кроме двух основных способов есть третий — подключение к книге как к базе данных через ADO и провайдер Microsoft ACE OLEDB. Лист читается SQL-запросом SELECT * FROM [Лист1$]. Способ быстрый, но требует установленного провайдера нужной разрядности, а тип колонки провайдер определяет по первым строкам — смешанные колонки (числа вперемешку с текстом) теряют значения. Сегодня его выбирают редко.
| Критерий | ТабличныйДокумент | COM Excel.Application | ADO (ACE OLEDB) |
|---|---|---|---|
| Нужен установленный Excel | Нет | Да | Нет, нужен провайдер ACE |
| Linux-сервер | Да | Нет | Нет |
| Скорость на 10 000 строк | Высокая | Низкая по ячейкам, высокая диапазоном | Высокая |
| Выбор листа | Только первый | Любой | Любой |
| Формулы | Только результат | Формулы и результат | Только результат |
| Риск зависших процессов | Нет | Да | Нет |
| Сложность кода | Низкая | Средняя | Средняя |
Короткий вывод: для новых разработок на управляемых формах берите табличный документ. COM оставьте для случаев, когда нужен конкретный лист или работа с формулами, и запускайте его на клиенте.
Проверка значений и обработка ошибок при загрузке
Excel не знает правил вашей базы. В колонке «Количество» окажется «12 шт», в колонке «Дата» — «31.02.2025», а в артикуле — пробел в конце. Проверяйте каждую строку до записи в базу и собирайте ошибки в список, а не прерывайте загрузку на первой.
Приведение строки к числу
Функция СтрокаВЧисло(Знач Текст, ЕстьОшибка)
Текст = СтрЗаменить(СокрЛП(Текст), " ", "");
Текст = СтрЗаменить(Текст, Символы.НПП, ""); // неразрывный пробел из Excel
Текст = СтрЗаменить(Текст, ",", ".");
ОписаниеТипа = Новый ОписаниеТипов("Число");
Число = ОписаниеТипа.ПривестиЗначение(Текст);
ЕстьОшибка = (Число = 0 И Текст <> "0" И Текст <> "");
Возврат Число;
КонецФункции
ОписаниеТипов.ПривестиЗначение не вызывает исключение: если строка не число, вернётся 0. Поэтому флаг ошибки поднимается отдельно — когда результат ноль, а в ячейке было что-то кроме нуля.
Сбор ошибок с номером строки
Ошибки = Новый Массив;
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
ЕстьОшибка = Ложь;
Количество = СтрокаВЧисло(ТабДок.Область(НомерСтроки, 3).Текст, ЕстьОшибка);
Если ЕстьОшибка Тогда
Ошибки.Добавить(СтрШаблон("Строка %1: количество «%2» не число",
Формат(НомерСтроки, "ЧГ=0"), ТабДок.Область(НомерСтроки, 3).Текст));
КонецЕсли;
КонецЦикла;
Покажите пользователю весь список сразу. Ему проще исправить файл один раз, чем запускать загрузку пять раз подряд.
Большие файлы: как не ждать загрузку полчаса
На файлах в 20–50 тысяч строк узким местом становится не чтение, а то, что вы делаете с каждой строкой.
Приёмы для COM
- ⚡ Читайте диапазон целиком. Каждое обращение
Cells(Строка, Колонка).Value— отдельный межпроцессный вызов. ЧтениеЛист.UsedRange.Valueвозвращает весь лист одним вызовом в видеCOMSafeArray, а методВыгрузить()превращает его в массив 1С. Перед боевым запуском проверьте в отладчике порядок индексов полученного массива на маленьком файле. - 🔕 Отключите лишнее.
Excel.ScreenUpdating = ЛожьиExcel.DisplayAlerts = Ложьдо открытия книги.
Приёмы для любого способа
- 🔍 Не ищите элемент справочника в цикле. Вызов
Справочники.Номенклатура.НайтиПоРеквизитуна каждой строке — это 50 000 запросов к базе. Соберите все артикулы в таблицу значений и одним запросом получите соответствие артикул → ссылка через временную таблицу. - 📦 Пишите порциями. Не создавайте документ на 50 000 строк одной транзакцией. Разбейте на части по 1000–5000 строк или по документу на группу.
- 🧹 Сворачивайте до записи. Если в файле один артикул встречается несколько раз,
ТаблицаДанных.Свернуть("Артикул", "Количество")уменьшит объём работы. - ⏳ Выносите в фоновое задание. Загрузка дольше минуты на клиенте подвешивает форму. Длительную обработку запускайте в фоне через механизм длительных операций БСП.
Пример поиска ссылок одним запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Артикул КАК Артикул
|ПОМЕСТИТЬ ВТ_Файл
|ИЗ
| &ТаблицаФайла КАК Т
|;
|ВЫБРАТЬ
| ВТ_Файл.Артикул КАК Артикул,
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| ВТ_Файл КАК ВТ_Файл
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ВТ_Файл.Артикул = Номенклатура.Артикул";
Запрос.УстановитьПараметр("ТаблицаФайла", ТаблицаАртикулов);
Соответствие = Запрос.Выполнить().Выгрузить();
Таблица значений, которую передают в запрос, должна иметь колонки с заданным типом. Создавайте колонку как ТаблицаАртикулов.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50))), иначе запрос выдаст ошибку о неопределённом типе.
Загружайте данные сначала в копию базы . Ошибка в сопоставлении колонок на 50 000 строк создаёт столько же неправильных записей, и откатить их вручную тяжело.