Как загрузить файл Excel в табличный документ 1С и разобрать ячейки

· 9 мин

Содержание

Прочитать Excel файл как ТабличныйДокумент в 1С 8.3 можно одной строкой: ТабДок.Прочитать(ИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение). Для формата xlsx платформа обходится без установленного Excel, поэтому код работает и на сервере под Linux.

Частое заблуждение — что для чтения Excel обязательно нужен COM-объект Excel.Application. Это путь из времён 8.2: он медленный, требует Excel на машине и падает на серверах без офиса. Встроенный метод проще и надёжнее, а COM остаётся запасным вариантом для редких задач.

Что подготовить до чтения и какой способ выбрать

Перед тем как писать код, ответьте на три вопроса.

  • 📁 Где лежит файл. Если пользователь выбирает его на своём компьютере, а код загрузки выполняется на сервере, файл придётся передать через временное хранилище. Сервер не видит диск клиента.
  • 📄 Какой формат. xlsx и mxl читаются платформой напрямую. Старый xls лучше заранее пересохранить в xlsx: так меньше сюрпризов с кодировками и форматами ячеек.
  • 🔢 Нужны ли типы. Если важны числа и даты как значения, а не как строки, читайте в режиме Значение. Если нужна строка ровно так, как она видна в Excel (например, артикул с ведущими нулями), подойдёт режим Текст.

Сравнение способов, которые встречаются на практике:

СпособКогда подходитОграничения и риски
ТабличныйДокумент.Прочитать()Основной вариант для xlsx и mxlСложные книги с несколькими листами и сводными таблицами читаются не всегда так, как ждёшь
COM Excel.ApplicationНужно работать с конкретным листом, формулами, макросамиТолько Windows, нужен Excel, медленно, зависшие процессы EXCEL.EXE
ADO / OLE DB (провайдер Microsoft ACE)Плоская таблица, нужен SQL-отбор по листуТолько Windows, нужен установленный провайдер нужной разрядности
Разбор xlsx как zip + XMLНет Excel и нужен полный контроль над структуройМного кода, общие строки и стили приходится разбирать вручную

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

Алгоритм: читаем Excel файл в объект ТабличныйДокумент

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

  1. На клиенте пользователь выбирает файл, и он помещается во временное хранилище.
  2. На сервере двоичные данные записываются во временный файл.
  3. Временный файл читается методом Прочитать в табличный документ.
  4. Временный файл удаляется, документ разбирается построчно.

Клиентская часть: выбор и передача файла

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

&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
    Если Не Результат Тогда
        Возврат; // пользователь отказался от выбора
    КонецЕсли;
    ЗагрузитьНаСервере(Адрес);
КонецПроцедуры

Последний параметр УникальныйИдентификатор привязывает данные во хранилище к форме. Когда форма закроется, платформа их освободит сама.

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

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

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

    ОбработатьТабличныйДокумент(ТабДок);
КонецПроцедуры

Расширение во временном имени — xlsx. Платформа определяет формат в том числе по нему, поэтому имя без расширения может дать ошибку чтения.

Хотите, чтобы пользователь сначала увидел, что загрузилось? Сделайте реквизит формы типа ТабличныйДокумент, выведите его на форму полем и присвойте ему прочитанный документ. Пользователь проверит данные глазами и только потом нажмёт «Загрузить».

Как обходить строки, колонки и области прочитанного документа

После чтения у документа есть два ключевых свойства: ВысотаТаблицы — номер последней заполненной строки, ШиринаТаблицы — номер последней колонки. Ячейка берётся методом Область(Строка, Колонка).

&НаСервере
Процедура ОбработатьТабличныйДокумент(ТабДок)
    ПерваяСтрокаДанных = 2; // в первой строке заголовки
    Для НомерСтроки = ПерваяСтрокаДанных По ТабДок.ВысотаТаблицы Цикл
        Артикул = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
        Если ПустаяСтрока(Артикул) Тогда
            Продолжить; // пустые и служебные строки пропускаем
        КонецЕсли;
        Наименование = СокрЛП(ТабДок.Область(НомерСтроки, 2).Текст);
        Цена = ЗначениеЯчейки(ТабДок, НомерСтроки, 3, 0);
        Количество = ЗначениеЯчейки(ТабДок, НомерСтроки, 4, 0);
        // дальше — поиск номенклатуры и запись в документ или регистр
    КонецЦикла;
КонецПроцедуры

Колонки по заголовкам, а не по номерам

Жёсткие номера колонок ломаются, как только поставщик добавит в прайс столбец. Надёжнее один раз прочитать строку заголовков и запомнить, где какая колонка:

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

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

Области и диапазоны

Область можно взять и прямоугольником: ТабДок.Область(2, 1, ТабДок.ВысотаТаблицы, 5). Есть и адресация в стиле R2C1:R100C5 — ТабДок.Область("R2C1:R100C5"). Это удобно, когда данные в файле начинаются не с первой строки, а после шапки из логотипа и реквизитов.

Несколько листов в книге

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

Как привести текст ячеек к числам, датам и ссылкам

В режиме Значение у области ячейки заполнено свойство Значение, а признак СодержитЗначение равен Истина. Числа приходят числами, даты — датами. В режиме Текст всё приходит строкой в том виде, как показывает Excel.

На практике одна и та же колонка бывает смешанной: часть цен введена числом, часть — текстом «1 250,00». Поэтому удобно иметь функцию, которая сама разберётся:

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

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

    Попытка
        Возврат Число(Текст);
    Исключение
        Возврат ПоУмолчанию;
    КонецПопытки;
КонецФункции

Неразрывный пробел Символы.НПП Excel любит ставить как разделитель тысяч. Обычный СтрЗаменить(Текст, " ", "") его не уберёт, и Число() упадёт.

Что ещё приходится приводить:

  • 📅 Даты. В режиме Значение дата приходит типом Дата. Если в файле дата записана текстом «15.03.2025», разберите её через СтрРазделить(Текст, ".") и Дата(Год, Месяц, День).
  • 🔤 Артикулы и коды. Ячейку «00125» Excel хранит как число 125, если её не отформатировали как текст. Берите Текст, а не Значение, и дополняйте нулями слева, если длина кода фиксированная.
  • 🔗 Ссылки на справочники. Наименование из файла превращайте в ссылку поиском по коду, артикулу или ИНН — так надёжнее, чем по наименованию. Ненайденные строки складывайте в отдельный список и показывайте пользователю после загрузки.
  • ✅ Булево. «Да», «да», «1», «+» — нормализуйте через НРег() и список допустимых значений.
Сопоставление полей
Артикул (текст)→Номенклатура (поиск по артикулу)
Наименование→Наименование для проверки
Цена (число или текст)→Цена, Число(15,2)
Количество→Количество, Число(15,3)
Дата поставки (дата или текст)→Дата

Ошибки чтения и нестандартные файлы

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

Ещё две ситуации, которые ловят на внедрениях:

  • 🙈 Скрытые строки и столбцы. Они тоже попадают в документ. Если поставщик прячет в файле служебные колонки, ориентируйтесь на заголовки, а не на номера.
  • 🧾 Апостроф в начале ячейки. Excel использует его как признак текста и не показывает. В свойство Текст он обычно не попадает, но если видите его в данных — уберите через СтрЗаменить.

Проверка файла до записи в базу

Хорошая загрузка сначала проверяет весь файл и только потом пишет. Порядок такой:

  1. Прочитайте строку заголовков и убедитесь, что все обязательные колонки на месте. Нет колонки — остановитесь с понятным сообщением, а не на сотой строке с непонятной ошибкой преобразования типа.
  2. Пройдите по строкам и соберите ошибки в таблицу значений: номер строки, колонка, что не так («артикул не найден», «цена не число»).
  3. Если ошибок нет — пишите данные. Если есть — покажите таблицу пользователю. Номер строки в ней совпадает с номером строки в Excel, поэтому исправлять файл легко.

Такой отчёт об отклонённых строках снимает почти все вопросы «почему не загрузилось» ещё до звонка разработчику.

Загрузку в рабочую базу сначала прогоните на копии. Ошибка в сопоставлении колонок легко превращает цену в количество — и исправлять потом сотни документов дольше, чем один раз проверить.

Как ускорить импорт тысяч строк

Цикл по Область(Стр, Кол) на файле в 50–100 тысяч строк идёт заметно долго: каждое обращение создаёт объект области. Есть приём, который знают немногие: отдать область табличного документа построителю запроса и получить сразу таблицу значений.

Область = ТабДок.Область(1, 1, ТабДок.ВысотаТаблицы, ТабДок.ШиринаТаблицы);
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(Область);
Построитель.Выполнить();
ТаблицаДанных = Построитель.Результат.Выгрузить();

Колонки таблицы значений получат имена из первой строки области. Поэтому заголовки должны быть уникальными и непустыми, иначе часть колонок назовётся служебными именами. Дальше с таблицей работают обычными методами: Найти, Свернуть, передача в запрос как источник через параметр.

Другие способы снять нагрузку:

  1. Поиск ссылок одним запросом. Не ищите номенклатуру по артикулу на каждой строке. Соберите все артикулы в массив, выполните один запрос с условием В (&Артикулы) и положите результат в соответствие «артикул → ссылка».
  2. Запись наборами. Для регистров сведений заполняйте один набор записей и записывайте его целиком, а не по одной записи.
  3. Порции и транзакции. Большой файл пишите порциями, например по 1000 строк в транзакции. Одна гигантская транзакция держит блокировки и при ошибке откатывает всё.
  4. Фоновое задание. Если загрузка идёт дольше минуты, запустите её в фоне. Форма не зависнет, а пользователь увидит прогресс.

Нужно хранить загруженный файл как документ 1С, без привязки к Excel? Сохраните его в собственном формате: ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.MXL). Так же работает и обратная конвертация — запись в ТипФайлаТабличногоДокумента.XLSX.

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

Нужен ли установленный Excel для метода Прочитать?
Для xlsx — нет, платформа разбирает файл сама. Excel нужен только при чтении через COM-объект.
Можно ли прочитать Excel на клиенте, без передачи на сервер?
Да, табличный документ доступен и на клиенте. Но загружать данные в базу всё равно придётся серверным вызовом, поэтому чаще удобнее сразу передать файл на сервер.
Чем режим Значение отличается от режима Текст?
В режиме Значение ячейки сохраняют тип: числа, даты, булево. В режиме Текст всё приходит строкой в том виде, как её показывает Excel, включая форматирование чисел.
Почему после чтения слетели форматы и ширина колонок?
Табличный документ переносит оформление приблизительно. Для загрузки данных это не важно: значения ячеек читаются корректно.
Как загрузить файл csv тем же способом?
csv — текстовый формат, его проще читать через ЧтениеТекста и СтрРазделить по разделителю. Табличный документ здесь лишний шаг.