При автоматизации загрузки данных из файлов Excel (особенно с расширением .xlsx) разработчики часто используют COM-соединение. Однако при работе на стороне сервера этот подход преподносит неприятные сюрпризы. Программа может неожиданно выдать диалоговое окно с предложением сохранить изменения, либо выполнение серверного кода полностью зависает на вызове функции ПолучитьCOMОбъект.
В этой статье мы подробно разберем природу обеих проблем, найдем способы их устранения при работе через COM, а также рассмотрим наиболее современный, быстрый и безопасный альтернативный вариант чтения файлов Excel без использования сторонних приложений на сервере.
Даже если мы открываем файл Excel исключительно для чтения данных и программно ничего в него не записываем, Microsoft Excel при закрытии книги может выдать интерактивный запрос: "Сохранить изменения в файле?". Это происходит из-за того, что при открытии документа Excel автоматически пересчитывает «летучие» формулы (например, функции СЕГОДНЯ(), ТДАТА()), обновляет внешние связи или переводит структуру файла в режим совместимости. На сервере этот невидимый диалог приводит к вечному ожиданию ответа пользователя, из-за чего сеанс зависает.
Давайте проанализируем четыре надежных способа предотвращения этого поведения в коде 1С:
Мы можем программно «обмануть» Excel, сообщив ему, что все изменения в книге уже сохранены. Для этого перед закрытием файла необходимо установить свойство Saved в значение Истина. Рассмотрим пример кода:
// Предположим, что Док — это полученный COM-объект книги Excel
Док.Saved = Истина;
Док.Application.Quit();
Если мы работаем с объектом всего приложения Excel (Excel.Application), мы можем глобально запретить вывод любых предупреждений и диалоговых окон. В этом случае Excel автоматически принимает решение по умолчанию (закрывает документ без сохранения изменений):
ЭксельПриложение = ПолучитьCOMОбъект("", "Excel.Application");
ЭксельПриложение.DisplayAlerts = Ложь; // Отключаем все интерактивные вопросы
// Выполняем чтение данных...
ЭксельПриложение.Quit();
Метод Close объекта книги (Workbook) принимает несколько необязательных параметров. Первый параметр указывает, нужно ли сохранять изменения перед закрытием. Передав в него значение Ложь (или 0), мы гарантируем закрытие без лишних вопросов:
// Закрываем конкретную книгу без сохранения изменений
Док.Close(Ложь);
Если файл изначально открывается через метод Open коллекции книг Workbooks, хорошей практикой является явное указание третьего параметра в значение Истина (режим ReadOnly):
ПутьКФайлу = "C:\Temp\MyFile.xlsx";
ЭксельПриложение = Новый COMОбъект("Excel.Application");
Книга = ЭксельПриложение.Workbooks.Open(ПутьКФайлу, , Истина);
// Работаем с файлом...
Книга.Close(Ложь);
ЭксельПриложение.Quit();
Зависание процесса выполнения на строке ПолучитьCOMОбъект(ВременныйФайлПоступлений) — классическая серверная проблема. При локальной работе под правами администратора на рабочем компьютере все работает отлично, но на серверной ОС Windows служба сервера 1С запускается в изолированном окружении. Выясним основные технические причины этого сбоя:
Причина 1: Отсутствие системных каталогов профиля Windows (Desktop)
Служба сервера 1С:Предприятия обычно работает под специальной системной учетной записью (например, USR1CV8 или NetworkService). При инициализации COM-объекта Microsoft Excel пытается обратиться к папкам рабочего стола (Desktop) внутри профиля пользователя. Если этих папок физически не существует в системном профиле, процесс excel.exe зависает в бесконечном цикле ожидания.
Чтобы решить эту проблему, выполним следующие шаги:
C:\Windows\SysWOW64\config\systemprofile\DesktopC:\Windows\System32\config\systemprofile\DesktopUSR1CV8), есть полные права доступа (чтение и запись) на созданный каталог Desktop.Причина 2: «Зависшие» фоновые процессы excel.exe
Если во время предыдущих запусков импорта данных произошла ошибка, или код 1С аварийно завершился до вызова метода Quit(), то в операционной системе сервера остаются висеть скрытые процессы excel.exe. Они монополизируют доступ к ресурсам и блокируют новые обращения через COM.
Решение: откройте Диспетчер задач Windows на сервере, перейдите на вкладку "Подробности" (Details), найдите все процессы excel.exe, запущенные от имени системных учетных записей или пользователя 1С, и принудительно завершите их.
Причина 3: Настройки безопасности DCOM
Иногда операционная система блокирует запуск COM-сервера Excel из-под учетной записи службы 1С. Для исправления ситуации запустите утилиту настройки системных компонентов (нажмите Win+R, введите dcomcnfg и нажмите Enter). Перейдите по пути: Службы компонентов -> Компьютеры -> Мой компьютер -> Настройка DCOM. Найдите в списке Microsoft Excel Application, откройте свойства и на вкладке "Безопасность" настройте права на запуск и активацию для пользователя службы сервера 1С.
Использование COM-объектов на сервере несет огромные риски стабильности: падение производительности, утечки памяти, зависимость от установленного пакета MS Office и жесткая привязка к операционной системе Windows. К счастью, платформа 1С:Предприятие 8.3 имеет встроенный функционал, позволяющий полностью отказаться от COM при чтении файлов .xlsx.
Объект ТабличныйДокумент в современных версиях платформы умеет напрямую импортировать файлы Excel без привлечения стороннего ПО. Давайте рассмотрим готовый и лаконичный пример, как прочитать данные из временного хранилища на сервере без создания COM-объектов:
&НаСервере
Процедура РаботаСФайламиНаСервере(АдресСтрокиДвоичныхДанных)
// Получаем двоичные данные файла из временного хранилища
СерверныеПоступленияДанные = ПолучитьИзВременногоХранилища(АдресСтрокиДвоичныхДанных);
// Создаем имя временного файла на сервере
ВременныйФайлПоступлений = ПолучитьИмяВременногоФайла("xlsx");
// Записываем полученные данные во временный файл
СерверныеПоступленияДанные.Записать(ВременныйФайлПоступлений);
// Инициализируем ТабличныйДокумент 1С
ТабДок = Новый ТабличныйДокумент;
Попытка
// Напрямую читаем файл Excel средствами платформы
ТабДок.Прочитать(ВременныйФайлПоступлений, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
ЗаписьЖурналаРегистрации("ИмпортФайла", УровеньЖурналаРегистрации.Ошибка, , ,
"Не удалось прочитать файл Excel: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Удаляем временный файл с диска сразу после прочтения, чтобы не засорять систему
Попытка
УдалитьФайлы(ВременныйФайлПоступлений);
Исключение
// Ошибка удаления не критична для процесса
КонецПопытки;
// Теперь мы можем обойти строки и колонки файла как обычную таблицу 1С!
КоличествоСтрок = ТабДок.ВысотаТаблицы;
КоличествоКолонок = ТабДок.ШиринаТаблицы;
Для НомерСтроки = 1 По КоличествоСтрок Цикл
// Проанализируем, например, значение первой колонки
ЗначениеЯчейки = ТабДок.Область(НомерСтроки, 1).Текст;
Если ЗначениеЗаполнено(ЗначениеЯчейки) Тогда
// Обрабатываем данные строки...
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот подход обладает колоссальными преимуществами:
ТабличныйДокумент происходит в разы быстрее, чем последовательный перебор ячеек через COM-интерфейс.Используйте встроенные механизмы платформы 1С для работы с файлами — это значительно упростит поддержку и сделает вашу информационную базу стабильной и быстродействующей!