Чтение Excel-файла программно в 1С 8.3: табличный документ, COM и ADO

· 10 мин

Содержание

Прочитать данные из 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).Текст);
        Результат.Добавить(Строка);

    КонецЦикла;

    Возврат Результат;

КонецФункции

Что здесь важно:

  1. ВысотаТаблицы и ШиринаТаблицы — число строк и колонок с данными. Цикл по ним не выходит за пределы заполненной области.
  2. Область(Строка, Колонка) возвращает одну ячейку. Номера начинаются с единицы, как в Excel.
  3. Второй параметр Прочитать — способ чтения значений. С вариантом Значение платформа берёт значения ячеек, а не их отображение. Без параметра, или со способом Текст, вы получите то, что видно на экране: число 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 = Неопределено;

КонецПроцедуры

Три момента, на которых чаще всего спотыкаются:

  1. Путь к файлу — полный. Workbooks.Open не знает текущий каталог 1С. Передавайте путь вида C:\Обмен\остатки.xlsx.
  2. Excel.Quit() в любом исходе. Если код упал между Open и Quit, процесс EXCEL.EXE остаётся висеть в памяти и держит файл. Поэтому Quit стоит и в ветке исключения.
  3. 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.ApplicationADO (ACE OLEDB)
Нужен установленный ExcelНетДаНет, нужен провайдер ACE
Linux-серверДаНетНет
Скорость на 10 000 строкВысокаяНизкая по ячейкам, высокая диапазономВысокая
Выбор листаТолько первыйЛюбойЛюбой
ФормулыТолько результатФормулы и результатТолько результат
Риск зависших процессовНетДаНет
Сложность кодаНизкаяСредняяСредняя

Короткий вывод: для новых разработок на управляемых формах берите табличный документ. COM оставьте для случаев, когда нужен конкретный лист или работа с формулами, и запускайте его на клиенте.

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

Проверка значений и обработка ошибок при загрузке

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 строк создаёт столько же неправильных записей, и откатить их вручную тяжело.

Частые вопросы

Можно ли прочитать Excel в 1С, если на компьютере нет Microsoft Office?
Да. Метод ТабличныйДокумент.Прочитать разбирает xlsx средствами платформы, Excel и LibreOffice для этого не нужны.
Как прочитать csv-файл, который пользователи называют «экселем»?
Csv — обычный текст. Читайте его через ЧтениеТекста построчно и делите строку по разделителю функцией СтрРазделить. Учтите кодировку: файлы из Excel часто сохранены в windows-1251.
Почему дата из ячейки пришла числом вроде 45321?
Так Excel хранит даты: количество дней от 30.12.1899. Если ячейка не отформатирована как дата, вы получаете это число. Прибавьте его в секундах к дате 30.12.1899 или попросите отформатировать колонку.
Как прочитать объединённые ячейки?
Значение хранится в левой верхней ячейке объединения, остальные пустые. При разборе запоминайте последнее непустое значение колонки и подставляйте его в следующие строки.
Можно ли записать данные обратно в тот же файл?
Через COM — да, методом Save книги. Табличный документ сохраняется методом Записать в новый файл, исходное оформление Excel при этом может измениться.