Разработка механизмов загрузки данных из внешних файлов — одна из самых частых задач программиста 1С. Однако многие сталкиваются с ситуацией, когда код, идеально работающий на клиенте, «намертво» зависает при попытке выполнить его на стороне сервера. Особенно часто это происходит при использовании COM-объекта Excel.Application.
В этой статье мы подробно разберем, почему возникают блокировки серверных процессов, как настроить сервер для работы с Excel и почему современный подход с использованием ТабличногоДокумента является более предпочтительным и стабильным.
Когда мы выполняем команду Новый COMОбъект("Excel.Application") на стороне сервера, система пытается запустить полноценное приложение Microsoft Excel в неинтерактивном сеансе. Разберем основные факторы, которые приводят к «зависанию» этого процесса:
USR1CV8), операционной системе требуются физические папки Desktop. Если их нет, процесс Excel запускается, но не может завершить инициализацию и «вечно» ждет доступа.
C:\Windows\SysWOW64\config\systemprofile\DesktopC:\Windows\System32\config\systemprofile\Desktop
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = Ложь;
Excel.Visible = Ложь;
Проанализируем более надежный способ, который не требует наличия установленного Excel на сервере и работает значительно быстрее — объект ТабличныйДокумент. Он умеет напрямую читать файлы форматов .xls и .xlsx.
Рассмотрим по шагам процесс загрузки файла с клиента на сервер и его последующее чтение:
Для начала нам нужно выбрать файл на компьютере пользователя и поместить его во временное хранилище, чтобы сервер смог к нему обратиться.
&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Excel файлы (*.xls;*.xlsx)|*.xls;*.xlsx";
Если Диалог.Выбрать() Тогда
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(ОписаниеОповещения, , Диалог.ПолноеИмяФайла, Ложь, УникальныйИдентификатор);
КонецЕсли;
КонецПроцедура
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Результат Тогда
ОбработатьФайлНаСервере(Адрес, ВыбранноеИмяФайла);
КонецЕсли;
КонецПроцедура
Теперь на сервере мы извлекаем данные из хранилища, записываем их во временный файл и считываем методом Прочитать().
&НаСервере
Процедура ОбработатьФайлНаСервере(Адрес, ИмяФайла)
// Определяем расширение для корректного создания временного файла
Расширение = ?(СтрНайти(НРег(ИмяФайла), "xlsx") > 0, ".xlsx", ".xls");
ВременныйПуть = ПолучитьИмяВременногоФайла(Расширение);
// Получаем данные из хранилища и сохраняем на диск сервера
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
ДвоичныеДанные.Записать(ВременныйПуть);
// Читаем в ТабличныйДокумент
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ВременныйПуть);
Исключение
Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Начинаем обход строк
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
// Работа с данными
КонецЦикла;
// Удаляем временный файл
УдалитьФайлы(ВременныйПуть);
КонецПроцедура
Многие программисты жалуются, что при использовании ТабличногоДокумента все данные считываются как строки, и их сложно преобразовывать в числа или даты. Выясним, как решать эту проблему профессионально.
1. Проблема неразрывных пробелов. Часто в Excel числа отформатированы с разделителями разрядов. При чтении в 1С там оказывается символ с кодом 160 (неразрывный пробел). Функция Число() выдаст ошибку. Рассмотрим решение:
ТекстЯчейки = ТабДок.Область(НомерСтроки, 2).Текст;
// Удаляем неразрывные пробелы и обычные пробелы
ЧистоеЗначение = СтрЗаменить(ТекстЯчейки, Символы.НПП, "");
ЧистоеЗначение = СтрЗаменить(ЧистоеЗначение, " ", "");
Попытка
Цена = Число(ЧистоеЗначение);
Исключение
Цена = 0;
КонецПопытки;
2. Использование свойства «Значение». Вы можете попытаться получить типизированное значение напрямую, если в самом файле Excel ячейка имела правильный формат (Числовой или Дата). Для этого нужно проверить свойство СодержитЗначение.
ОбластьЯчейка = ТабДок.Область(НомерСтроки, 2);
Если ОбластьЯчейка.СодержитЗначение Тогда
НужноеЗначение = ОбластьЯчейка.Значение; // Здесь уже может быть Тип("Число") или Тип("Дата")
Иначе
НужноеЗначение = ОбластьЯчейка.Текст;
КонецЕсли;
Разберем, какой метод выбрать. Если вам нужно просто прочитать данные из таблицы, использование ТабличногоДокумента — лучший выбор. Он не зависит от установленного Microsoft Office, работает на Linux-серверах и не подвержен зависаниям из-за отсутствия папок профиля.
Если же стоит задача сложного форматирования Excel-файла (создание сводных таблиц, макросов, отрисовка сложных диаграмм), тогда придется использовать COM-объект. В этом случае обязательно проверьте наличие папок Desktop в системных профилях и установите права доступа для пользователя USR1CV8.
Проанализировав ситуацию, можно сделать вывод: стабильность серверного кода напрямую зависит от минимизации зависимостей от внешних тяжелых приложений. Переход на встроенные средства 1С для работы с файлами — это стандарт современной разработки.