При переходе с обычных форм на управляемые разработчики часто сталкиваются с ситуацией: привычный код для работы с таблицами Microsoft Excel перестает отображать графическое окно приложения, а последующие вызовы методов работы с ячейками завершаются критическими ошибками. Разберем детально, почему это происходит, в чем заключается специфика работы серверного контекста 1С и какими способами можно правильно и быстро загружать данные из табличных файлов.
Проанализируем типовую ситуацию: в серверной процедуре (директива &НаСервере) создается объект Excel.Application и устанавливается свойство Excel.Visible = 1. Однако окно на экране пользователя не появляется. Выясним технические причины такого поведения:
rphost) работает в отдельной системной сессии Windows, которая полностью изолирована от интерактивного рабочего стола пользователя. Любое приложение, запущенное службой, физически не имеет доступа к графическому экрану текущего терминального или локального сеанса. Окно открывается исключительно внутри контекста учетной записи службы.Select() и Activate(): Попытка использовать интерактивное позиционирование (например, Лист.Cells(н, 1).Select()) в скрытом фоновом режиме или под системной службой гарантированно приводит к исключению COM. Данные методы предназначены только для управления курсором в графическом интерфейсе. При программной обработке обращаться к данным следует напрямую через свойство Value или Value2.EXCEL.EXE, блокировке потоков и утечкам оперативной памяти. Для минимальной инициализации COM на сервере часто требуются дополнительные настройки прав DCOM и наличие каталогов Desktop в профиле systemprofile.Наиболее надежный, кроссплатформенный и быстрый способ, встроенный в платформу 1С:Предприятие 8.3 — использование объекта ТабличныйДокумент. Он не требует установленного Microsoft Office, работает на Linux и Windows, и полностью исключает зависимость от COM-соединений.
Схема работы строится следующим образом: пользователь на клиенте выбирает файл, файл помещается во временное хранилище и передается на сервер, где считывается напрямую в ТабличныйДокумент.
Посмотрим на пример клиентского кода:
&НаКлиенте
Процедура ЗагрузитьФайлНаКлиенте(Команда)
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Заголовок = "Выберите файл Excel для загрузки";
ПараметрыДиалога.Фильтр = "Файлы Excel (*.xlsx;*.xls)|*.xlsx;*.xls";
Оповещение = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект);
НачатьПомещениеФайлаНаСервер(Оповещение, , , ПараметрыДиалога, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораФайла(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
ПрочитатьФайлНаСервере(Результат.Адрес);
КонецПроцедуры
Разберем серверную часть обработки файла:
&НаСервере
Процедура ПрочитатьФайлНаСервере(АдресВХранилище)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХранилище);
ВременныйФайл = ПолучитьИмяВременногоФайла("xlsx");
ДвоичныеДанные.Записать(ВременныйФайл);
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ВременныйФайл, СпособЧтенияЗначенийТабличногоДокумента.Значение);
УдалитьФайлы(ВременныйФайл);
ВсегоСтрок = ТабДок.ВысотаТаблицы;
ВсегоКолонок = ТабДок.ШиринаТаблицы;
Для НомерСтроки = 2 По ВсегоСтрок Цикл
ЗначениеКолонки1 = ТабДок.Область(НомерСтроки, 1).Текст;
ЗначениеКолонки2 = ТабДок.Область(НомерСтроки, 2).Текст;
// Выполняем заполнение реквизитов документа или справочника
КонецЦикла;
КонецПроцедуры
Если специфика задачи требует обязательного отображения окна Excel пользователю или использования специфических макросов, весь COM-объект необходимо инициализировать в контексте &НаКлиенте. На клиенте считываем данные, упаковываем их в структуры и массивы, после чего единым пакетом передаем на сервер для записи в базу данных.
Рассмотрим реализацию данного подхода:
&НаКлиенте
Процедура ЗагрузитьЧерезCOMНаКлиенте(ПутьКФайлу)
Попытка
Excel = Новый COMObject("Excel.Application");
Исключение
Сообщить("Не удалось запустить Excel: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
Excel.Visible = Истина; // Окно отобразится пользователю
Книга = Excel.Workbooks.Open(ПутьКФайлу);
Лист = Книга.WorkSheets(1);
ТаблицаДанных = Новый Массив;
ВсегоСтрок = Лист.UsedRange.Rows.Count;
// Обращение напрямую к свойству Value без методов Select и Activate
Для НомерСтроки = 2 По ВсегоСтрок Цикл
СтрокаДанных = Новый Структура;
СтрокаДанных.Вставить("Артикул", СокрЛП(Лист.Cells(НомерСтроки, 1).Value));
СтрокаДанных.Вставить("Количество", Лист.Cells(НомерСтроки, 2).Value);
СтрокаДанных.Вставить("Цена", Лист.Cells(НомерСтроки, 3).Value);
ТаблицаДанных.Добавить(СтрокаДанных);
КонецЦикла;
Книга.Close(Ложь);
Excel.Quit();
Excel = Неопределено;
// Передаем собранный массив на сервер для записи
ЗаписатьДанныеВДокументНаСервере(ТаблицаДанных);
КонецПроцедуры
Файлы современного формата .xlsx представляют собой сжатые ZIP-архивы, содержащие таблицы в формате XML. При необходимости обработать сотни тысяч строк с максимальной производительностью без участия сторонних программ можно применить объекты ЧтениеZipФайла и ЧтениеXML.
ЧтениеZipФайла./xl/sharedStrings.xml./xl/worksheets/sheet1.xml потоковым объектом ЧтениеXML.Этот подход обеспечивает предельную скорость парсинга больших объемов данных как на клиенте, так и на сервере.
Еще один способ быстро прочитать файл Excel без визуального открытия приложения — использование технологии ADO. В этом случае файл воспринимается как база данных, а листы — как таблицы.
Разберем пример подключения через OLE DB:
&НаСервере
Процедура ПрочитатьЧерезADO(ПутьКФайлу)
Соединение = Новый COMObject("ADODB.Connection");
СтрокаПодключения = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + ПутьКФайлу + ";Extended Properties=""Excel 12.0 XML;HDR=YES;"";";
Попытка
Соединение.Open(СтрокаПодключения);
НаборЗаписей = Новый COMObject("ADODB.Recordset");
НаборЗаписей.Open("SELECT * FROM [Лист1$]", Соединение);
Пока Не НаборЗаписей.EOF() Цикл
Значение1 = НаборЗаписей.Fields(0).Value;
Значение2 = НаборЗаписей.Fields(1).Value;
НаборЗаписей.MoveNext();
КонецЦикла;
НаборЗаписей.Close();
Соединение.Close();
Исключение
Сообщить("Ошибка чтения через ADO: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Итог: Для стабильной работы клиент-серверной архитектуры 1С следует отказаться от серверной COM-автоматизации Excel в пользу платформенного объекта ТабличныйДокумент или передачи предварительно собранных структур с клиента на сервер.