Чтение xls и xlsx из встроенного языка 1С:Предприятия 8.3 без сюрпризов

· 10 мин

Содержание

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

Типичная ситуация: поставщик присылает прайс на 3 000 строк, менеджер просит «кнопку, чтобы цены сами встали в 1С». Ниже код для такой загрузки на платформе 1С:Предприятие 8.3 в управляемом интерфейсе. Задача общая для платформы и от конфигурации (БП, УТ, ЗУП) не зависит.

Какой метод доступа к Excel выбрать до написания кода

Выбор зависит от трёх вещей: где выполняется код, стоит ли там Microsoft Office и насколько файл «аккуратный».

СпособЧто нужно на машинеГде работаетКогда брать
ТабличныйДокумент.Прочитать()Ничего, только платформа 8.3Сервер (Windows и Linux), толстый и тонкий клиентПочти всегда, это вариант по умолчанию
COM Excel.ApplicationУстановленный ExcelТолько WindowsНужен конкретный лист, формулы, форматирование
ADO (ADODB.Connection)Microsoft Access Database Engine той же разрядности, что и 1СТолько WindowsСтрогая таблица с шапкой, нужен SQL-отбор по листу

Перед стартом проверьте три момента:

  • 🖥️ Разрядность. 64-битный сервер 1С не увидит 32-битный провайдер ACE и наоборот. Для COM то же самое ограничение по Office не так жёсткое, но Excel на сервере — отдельная история (о ней ниже).
  • 📁 Где лежит файл. Код на сервере не видит диск пользователя. Файл сначала передают на сервер через временное хранилище.
  • 📄 Формат. Для ТабличныйДокумент надёжнее xlsx. Старый xls, если чтение падает, пересохраните в xlsx — это быстрее, чем искать причину.
Как читать ваш файл Excel?

Нативное чтение Excel через объект ТабличныйДокумент

Начиная с платформы 8.3.6 метод Прочитать() понимает xlsx. Табличный документ загружает лист со значениями, объединениями и форматированием. Дальше с ним работают как с обычным макетом.

Шаг 1. Передать файл с клиента на сервер

Пользователь выбирает файл на своём компьютере, платформа помещает его во временное хранилище. Этот вариант одинаково работает в тонком и веб-клиенте.

&НаКлиенте
Процедура ЗагрузитьИзExcel(Команда)
	Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
	НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры

&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
	Если Не Результат Тогда
		Возврат; // пользователь отменил выбор
	КонецЕсли;
	Расширение = НРег(Сред(Новый Файл(ВыбранноеИмяФайла).Расширение, 2));
	Если Расширение <> "xlsx" И Расширение <> "xls" Тогда
		Сообщить("Выберите файл Excel (xlsx или xls).");
		Возврат;
	КонецЕсли;
	Ошибки = Новый Массив;
	Строки = ПрочитатьФайлНаСервере(Адрес, Расширение, Ошибки);
	Для Каждого ТекстОшибки Из Ошибки Цикл
		Сообщить(ТекстОшибки);
	КонецЦикла;
	Сообщить("Прочитано строк: " + Формат(Строки.Количество(), "ЧГ=0"));
КонецПроцедуры

Шаг 2. Записать двоичные данные во временный файл и прочитать

Метод Прочитать() принимает имя файла, а не двоичные данные. Поэтому на сервере файл из хранилища записывают во временный каталог, читают и сразу удаляют.

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

	ТабДок = Новый ТабличныйДокумент;
	Попытка
		ТабДок.Прочитать(ИмяВременногоФайла);
	Исключение
		УдалитьФайлы(ИмяВременногоФайла);
		ВызватьИсключение "Не удалось прочитать файл Excel: " + ОписаниеОшибки();
	КонецПопытки;
	УдалитьФайлы(ИмяВременногоФайла);

	Возврат РазобратьТабличныйДокумент(ТабДок, Ошибки);
КонецФункции

В новых версиях платформы у Прочитать() есть второй параметр — способ чтения значений (СпособЧтенияЗначенийТабличногоДокумента.Текст или .Значение). В режиме «Значение» числа и даты приходят типизированными. Если ваша платформа его поддерживает, это избавляет от части преобразований из шага 4.

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

Построчный разбор: как прочитать данные из Excel файла в таблицу 1С

Главная ошибка новичков — привязка к номерам колонок: «артикул во второй, цена в пятой». Через месяц поставщик добавит колонку «Бренд», и цены поедут в количество. Надёжнее найти колонки по заголовкам в первой строке.

Шаг 3. Карта колонок по заголовкам

&НаСервереБезКонтекста
Функция ТекстЯчейки(ТабДок, НомСтр, НомКол)
	Возврат СокрЛП(ТабДок.Область(НомСтр, НомКол, НомСтр, НомКол).Текст);
КонецФункции

&НаСервереБезКонтекста
Функция РазобратьТабличныйДокумент(ТабДок, Ошибки)
	Результат = Новый Массив;
	Высота = ТабДок.ВысотаТаблицы;
	Ширина = ТабДок.ШиринаТаблицы;

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

	Для Каждого ИмяКолонки Из СтрРазделить("артикул,наименование,количество,цена", ",") Цикл
		Если Колонки[ИмяКолонки] = Неопределено Тогда
			Ошибки.Добавить("В первой строке файла нет колонки «" + ИмяКолонки + "».");
		КонецЕсли;
	КонецЦикла;
	Если Ошибки.Количество() > 0 Тогда
		Возврат Результат;
	КонецЕсли;

Шаг 4. Цикл по строкам с преобразованием типов

	Для НомСтр = 2 По Высота Цикл
		Артикул = ТекстЯчейки(ТабДок, НомСтр, Колонки["артикул"]);
		Если Не ЗначениеЗаполнено(Артикул) Тогда
			Продолжить; // пустая или итоговая строка
		КонецЕсли;

		ОшибкаЧисла = Ложь;
		Количество = СтрокаВЧисло(ТекстЯчейки(ТабДок, НомСтр, Колонки["количество"]), ОшибкаЧисла);
		Цена = СтрокаВЧисло(ТекстЯчейки(ТабДок, НомСтр, Колонки["цена"]), ОшибкаЧисла);
		Если ОшибкаЧисла Тогда
			Ошибки.Добавить(СтрШаблон("Строка %1: количество или цена не число.", Формат(НомСтр, "ЧГ=0")));
			Продолжить;
		КонецЕсли;

		Строка = Новый Структура("Артикул, Наименование, Количество, Цена");
		Строка.Артикул = Артикул;
		Строка.Наименование = ТекстЯчейки(ТабДок, НомСтр, Колонки["наименование"]);
		Строка.Количество = Количество;
		Строка.Цена = Цена;
		Результат.Добавить(Строка);
	КонецЦикла;

	Возврат Результат;
КонецФункции

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

Почему так:

  • 🔢 Неразрывный пробел. Excel показывает «1 234,56» с разделителем групп разрядов. В тексте ячейки это часто Символы.НПП, а не обычный пробел, и Число() на нём падает.
  • 📦 Массив структур, а не таблица значений. ТаблицаЗначений нельзя вернуть на клиент. Массив структур с примитивами передаётся без проблем.
  • 🧾 Ошибки копятся, а не обрывают загрузку. Пользователь видит сразу все плохие строки с номерами, а не правит файл по одной ошибке за запуск.

Даты из Excel

Дата в ячейке приходит двумя способами:

  1. Текстом по формату ячейки, например 01.02.2025. Разберите через СтрРазделить(Текст, ".") и соберите Дата(Год, Месяц, День).
  2. Числом вроде 45689, если ячейка без формата даты. Это порядковый номер дня Excel. Перевод: Дата(1899, 12, 30) + Число * 86400. Для 45689 получится 01.02.2025.

Чтение данных через COM-объект Excel

COM запускает настоящий Excel и управляет им из 1С. Это даёт полный доступ к книге: листы по имени, формулы, цвета. Цена — зависимость от установленного Office и скорость.

&НаКлиенте
Процедура ПрочитатьЧерезCOM(ИмяФайла)
	Excel = Новый COMОбъект("Excel.Application");
	Excel.DisplayAlerts = Ложь;
	Попытка
		Книга = Excel.Workbooks.Open(ИмяФайла, 0, Истина); // без обновления связей, только чтение
		Лист = Книга.Worksheets("Прайс");
		Диапазон = Лист.UsedRange;
		ПоследняяСтрока = Диапазон.Row + Диапазон.Rows.Count - 1;

		Для НомСтр = 2 По ПоследняяСтрока Цикл
			Артикул = СокрЛП(Лист.Cells(НомСтр, 1).Text);
			Если Артикул = "" Тогда
				Продолжить;
			КонецЕсли;
			Цена = Лист.Cells(НомСтр, 5).Value; // число придёт числом, пустая ячейка — Неопределено
			// ... дальше обработка строки
		КонецЦикла;

		Книга.Close(Ложь);
	Исключение
		Excel.Quit();
		Excel = Неопределено;
		ВызватьИсключение;
	КонецПопытки;
	Excel.Quit();
	Excel = Неопределено;
КонецПроцедуры

Три приёма, без которых COM-загрузка доставляет проблемы:

  • 🧟 Всегда Excel.Quit(), в том числе в ветке Исключение. Иначе после каждой ошибки в диспетчере задач остаётся висящий EXCEL.EXE. За день тестов их набирается десяток, и файл оказывается «занят».
  • 📖 Открывайте только на чтение (третий параметр Open — Истина). Тогда открытый у пользователя файл не мешает, а книга не попросит сохранить изменения.
  • 🔎 .Text и .Value — разные вещи. .Text отдаёт то, что видно на экране (с форматом и «####» в узкой колонке). .Value — само значение: число, дату 1С или Неопределено для пустой ячейки.

Не запускайте Excel через COM на сервере 1С. Microsoft не поддерживает автоматизацию Office из служб: Excel под служебной учётной записью может зависнуть на невидимом диалоге и заблокировать рабочий процесс. COM-вариант — только на клиенте Windows.

Чтение листа Excel через ADO как таблицы

ADO читает лист как таблицу базы данных. Excel для этого не нужен, но нужен провайдер Microsoft ACE OLEDB той же разрядности, что и процесс 1С.

Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ИмяФайла
	+ ";Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1"";");
Набор = Соединение.Execute("SELECT * FROM [Прайс$]");
Пока Не Набор.EOF Цикл
	Артикул = Набор.Fields.Item("Артикул").Value;
	Цена = Набор.Fields.Item("Цена").Value;
	// ... обработка
	Набор.MoveNext();
КонецЦикла;
Набор.Close();
Соединение.Close();

Параметры строки подключения:

  • HDR=YES — первая строка считается шапкой, к полям обращаются по именам заголовков.
  • IMEX=1 — смешанные колонки (где есть и числа, и текст) читаются как текст. Без него провайдер угадывает тип по первым строкам, и «неподходящие» значения превращаются в NULL.
  • [Прайс$] — имя листа со знаком доллара. Можно добавить WHERE, чтобы отсеять пустые строки ещё до цикла.

Сравнение скорости чтения Excel в 1С разными методами

Точное время зависит от машины и файла, поэтому ориентируйтесь на соотношение, а не на секунды.

МетодСкорость на тысячах строкУзкое место
COM, ячейка за ячейкой через Cells()Самый медленныйКаждое обращение — межпроцессный вызов к Excel
COM, весь диапазон одним Range.ValueБыстрыйСам запуск Excel, разбор массива
ТабличныйДокумент.Прочитать()БыстрыйОбращение к ячейкам через Область() в цикле
ADOБыстрыйПодключение провайдера, капризы с типами

Если COM всё-таки нужен, читайте диапазон целиком: Значения = Лист.UsedRange.Value вернёт объект COMSafeArray, а его метод Выгрузить() — массив 1С. Порядок измерений в полученном массиве проверьте на файле из двух-трёх строк, прежде чем писать обработку на 50 000.

Для табличного документа ускорение одно: не вызывайте ВысотаТаблицы и ШиринаТаблицы внутри цикла, запоминайте их в переменных, как в примере выше.

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

Прочитать файл — половина работы. Вторая половина — не пустить в базу мусор.

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

Что проверять в каждой строке до записи в базу:

  1. Обязательные поля. Пустой артикул — пропуск строки, пустая цена — ошибка с номером строки.
  2. Тип и диапазон. Количество не отрицательное, цена не больше разумного предела. Цена 1 500 000 за болт — почти всегда сдвиг колонок.
  3. Дубли в самом файле. Соберите артикулы в Соответствие и сообщайте о повторе, а не перезаписывайте молча.
  4. Сопоставление со справочником. Ищите номенклатуру одним запросом по массиву артикулов после чтения, а не НайтиПоРеквизиту() в цикле по каждой строке.
  5. Объединённые ячейки. Значение хранится только в левой верхней ячейке объединения, остальные пустые. Шапки из двух строк с объединениями разбирайте отдельно.

Запись документов делайте после проверки всего файла и в одной транзакции. Если в строке 2 815 из 3 000 ошибка, лучше не записать ничего, чем получить половину прайса.

Частые вопросы про чтение Excel в 1С

Можно ли прочитать Excel в 1С без программирования?
Да. Во многих документах типовых конфигураций в табличной части есть команда загрузки из файла (обычно в меню «Ещё»). Там же сопоставляются колонки. Код нужен, когда загрузка нестандартная.
Работает ли чтение xlsx на сервере 1С под Linux?
Да, если использовать ТабличныйДокумент.Прочитать(). COM и ADO на Linux недоступны.
Читает ли ТабличныйДокумент формулы из Excel?
Нет, он получает рассчитанные значения, сохранённые в файле. Если нужны сами формулы, используйте COM и свойство Formula ячейки.
Как прочитать csv, который открывается в Excel?
Это обычный текст. Читайте его через ЧтениеТекста построчно и делите строки по разделителю функцией СтрРазделить(). Excel для этого не нужен.
Можно ли читать Excel в фоновом задании?
Да, через ТабличныйДокумент на сервере: передайте адрес временного хранилища в параметры задания. COM в фоновом задании не используйте.