Как прочитать файл Excel в табличный документ 1С без использования COM-объекта Excel.Application

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Чтение файлов Excel — одна из самых частых задач в практике разработчика 1С. Традиционный метод с использованием COM-соединения Excel.Application постепенно уходит в прошлое. Он медленный, требует обязательной установки Microsoft Office на компьютере или сервере, жестко привязан к операционной системе Windows и часто приводит к зависанию процессов в оперативной памяти.

В этой статье мы подробно разберем, как правильно реализовать чтение файлов Excel в штатный ТабличныйДокумент в управляемом приложении 1С, избежав типичных ошибок с правами доступа и файловыми операциями на сервере. Также мы рассмотрим альтернативные и очень быстрые способы разбора полученных данных.

Почему нельзя прочитать файл Excel напрямую на клиенте?

Прежде чем перейти к коду, давайте проанализируем важное ограничение платформы 1С:Предприятие. Метод ТабличныйДокумент.Прочитать() недоступен в Тонком и Веб-клиентах. Разработчики платформы сделали это ограничение намеренно, так как обработка тяжелых бинарных файлов требует значительных ресурсов, которые должны выделяться на стороне сервера.

Попытка прочитать файл на клиенте без обращения к серверу штатными методами платформы невозможна. Единственный правильный архитектурный путь в управляемом приложении выглядит следующим образом:

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

Разберем этот процесс по шагам и выясним, почему часто возникает популярная ошибка «Ошибка при выполнении файловой операции».

Шаг 1. Передача файла с клиента на сервер через временное хранилище

Для безопасной передачи файла на сервер мы будем использовать асинхронный метод НачатьПомещениеФайлаНаСервер() (или его аналог НачатьПомещениеФайла() в более ранних версиях платформы). Это позволяет избежать зависания интерфейса у пользователя при загрузке больших файлов.

Рассмотрим пример клиентского кода:


&НаКлиенте
Процедура ВыбратьИЗагрузитьФайлExcel(Команда)

    // Настраиваем диалог выбора файла
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Файлы Excel (*.xls;*.xlsx)|*.xls;*.xlsx";
    Диалог.МножественныйВыбор = Ложь;
    Диалог.Заголовок = "Выберите файл Excel для импорта";
    
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект);
    Диалог.Показать(ОписаниеОповещения);

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

&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт

    Если ВыбранныеФайлы = Неопределено Или ВыбранныеФайлы.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ПутьКФайлу = ВыбранныеФайлы[0];
    ФайлИнфо = Новый Файл(ПутьКФайлу);
    РасширениеФайла = ФайлИнфо.Расширение; // Сохраняем расширение (например, ".xlsx")
    
    // Подготавливаем параметры для помещения файла в хранилище
    ОповещениеОкончания = Новый ОписаниеОповещения("ИмпортФайлаЗавершен", ЭтотОбъект, РасширениеФайла);
    НачатьПомещениеФайлаНаСервер(ОповещениеОкончания, , , , ПутьКФайлу, УникальныйИдентификатор);

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

Шаг 2. Получение файла на сервере и решение проблемы с правами доступа

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

Важный нюанс: Многие разработчики пытаются использовать метод КаталогВременныхФайлов() для создания пути к файлу на сервере вручную (например, складывая путь и фиксированную строку "temp.xlsx"). Это грубая ошибка, которая приводит к двум проблемам:

  1. Permission Denied (Доступ запрещен): У службы, под которой запущен сервер 1С (обычно это пользователь usr1cv8), может не быть прав на запись в общие системные папки компьютера.
  2. Конфликт сессий: Если два пользователя одновременно запустят импорт, они попытаются записать данные в один и тот же файл temp.xlsx, что вызовет ошибку блокировки файла другим процессом.

Для решения этой проблемы мы должны использовать метод ПолучитьИмяВременногоФайла(). Он генерирует абсолютно уникальное имя файла в специальной изолированной временной папке сервера 1С, к которой у процесса rphost гарантированно есть полные права доступа.

Также критически важно передать в метод ПолучитьИмяВременногоФайла() исходное расширение файла. Платформа 1С определяет алгоритм разбора файла (старый бинарный формат BIFF8 для .xls или современный XML-пакет для .xlsx) исключительно по его расширению. Если передать файл с расширением по умолчанию (.tmp), метод ТабДок.Прочитать() выдаст ошибку файловой операции.

Посмотрим на реализацию серверной части:


&НаКлиенте
Процедура ИмпортФайлаЗавершен(РезультатПомещения, ДополнительныеПараметры) Экспорт

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

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

&НаСервереБезКонтекста
Процедура ПрочитатьФайлНаСервере(Знач АдресХранилища, Знач РасширениеФайла, ТабличныйДок)

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

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

Шаг 3. Чтение нескольких листов книги Excel

Когда мы читаем многостраничный документ Excel через метод ТабличныйДокумент.Прочитать(), платформа 1С загружает все листы книги в один документ. При этом каждый лист помещается в отдельную именованную область.

Мы можем легко управлять этим процессом и обращаться к конкретным страницам книги. Проанализируем, как получить список всех загруженных листов и работать с ними по отдельности:


&НаСервереБезКонтекста
Процедура РазборЛистовКниги(ТабличныйДок)

    // Каждому листу Excel соответствует именованная область с аналогичным именем
    Для Каждого Область Из ТабличныйДок.Области Цикл
        
        ИмяЛиста = Область.Имя;
        Сообщить("Обнаружен лист Excel с именем: " + ИмяЛиста);
        
        // Мы можем получить область конкретного листа для дальнейшей обработки
        ОбластьЛиста = ТабличныйДок.Область(ИмяЛиста);
        
        // Например, узнаем высоту (количество строк) конкретного листа
        КоличествоСтрок = ОбластьЛиста.ВысотаТаблицы;
        Сообщить("Количество строк на листе: " + КоличествоСтрок);
        
    КонецЦикла;

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

Шаг 4. Лайфхак: Быстрая конвертация ТабличногоДокумента в ТаблицуЗначений

Зачастую нам нужно не просто показать Excel на форме, а быстро обработать его данные: перебрать строки, загрузить их в справочник или документ. Перебор ячеек табличного документа в цикле Для Строка = 1 По ВысотаТаблицы... — процесс медленный.

Существует изящный способ мгновенной конвертации табличного документа (или его отдельного листа) в стандартную ТаблицуЗначений с помощью объекта ПостроительЗапроса. Этот метод работает в десятки раз быстрее ручного обхода ячеек.

Рассмотрим, как это реализовать на практике:


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

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

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

Важные требования при работе с этим лайфхаком:

Альтернативный вариант: NativeXLSX на клиенте через ЧтениеZipФайла

Если вам перед разработкой поставлена жесткая задача — «вообще не использовать серверные вызовы» (например, в распределенных мобильных клиентах с низкой пропускной способностью сети), то для формата .xlsx существует обходной путь.

Формат .xlsx — это обычный ZIP-архив, содержащий XML-файлы. Вы можете использовать объект ЧтениеZipФайла прямо на клиенте, распаковать архив во временный каталог и прочитать файлы разметки с помощью объекта ЧтениеXML:

Этот метод чрезвычайно быстрый и полностью кроссплатформенный (работает в веб-клиенте на любой ОС), но требует написания сложного парсера XML-структуры Excel «вручную» и не поддерживает старый формат .xls.

Резюме

Мы выяснили, что оптимальный, стабильный и безопасный способ чтения Excel в 1С — это использование встроенного метода Прочитать() объекта ТабличныйДокумент на стороне сервера. Главное — правильно организовывать передачу файлов через временное хранилище, использовать ПолучитьИмяВременногоФайла() с передачей верного расширения (xls/xlsx) и не бояться применять ПостроительЗапроса для мгновенного получения готовой таблицы значений.

← На главную