Загрузка данных из файлов Excel — одна из самых частых задач в 1С. Однако при переходе на управляемые формы и работу через веб-сервер (веб-клиент или тонкий клиент через http/https) привычные методы, работавшие годами, начинают выдавать ошибки. Рассмотрим, почему классический подход с COMОбъект не подходит для современной архитектуры и как правильно реализовать загрузку, используя возможности платформы 8.3.
Когда база опубликована на веб-сервере, код исполняется в разных контекстах. Разберем типичную ошибку начинающего разработчика: попытку открыть файл по прямому пути на сервере. Процедура на стороне сервера не имеет доступа к файловой системе вашего локального компьютера. Когда вы передаете строку C:\MyFiles\Data.xlsx в серверный метод, сервер ищет этот файл у себя на диске, не находит его и возвращает ошибку.
Кроме того, использование COMОбъект("Excel.Application") на сервере — это крайне нестабильное решение. Для его работы на сервере должен быть установлен Microsoft Office, настроены права DCOM, а при работе под Linux этот метод вовсе не применим. Поэтому мы разберем более надежный и современный способ через ТабличныйДокумент.
Первым делом нам необходимо позволить пользователю выбрать файл на его компьютере и «протолкнуть» этот файл в облако (на сервер). Для этого используется временное хранилище. Рассмотрим, как выглядит процедура выбора файла на клиенте.
&НаКлиенте
Процедура ИмяФайлаДанныхНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = ЛОЖЬ;
// Создаем диалог выбора
ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытияФайла.Заголовок = "Выберите файл Excel";
ДиалогОткрытияФайла.Фильтр = "Файлы Excel(*.xls; *.xlsx)|*.xls; *.xlsx";
ДиалогОткрытияФайла.МножественныйВыбор = ЛОЖЬ;
Если ДиалогОткрытияФайла.Выбрать() Тогда
Объект.ИмяФайлаДанных = ДиалогОткрытияФайла.ПолноеИмяФайла;
КонецЕсли;
КонецПроцедуры
Важно помнить: простое сохранение пути в реквизит ИмяФайлаДанных ничего не даст серверу. Нам нужно прочитать файл в двоичные данные и поместить их во временное хранилище. Проанализируем код основной процедуры запуска чтения:
&НаКлиенте
Процедура ВыполнитьЗагрузку(Команда)
// Для веб-клиента обязательно подключаем расширение работы с файлами
#Если ВебКлиент Тогда
ПодключитьРасширениеРаботыСФайлами();
#КонецЕсли
ФайлНаКлиенте = Новый Файл(Объект.ИмяФайлаДанных);
Если Не ФайлНаКлиенте.Существует() Тогда
Сообщить("Указанный файл не найден на вашем компьютере!");
Возврат;
КонецЕсли;
// Читаем файл в двоичные данные и отправляем на сервер
ДвоичныеДанные = Новый ДвоичныеДанные(Объект.ИмяФайлаДанных);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
// Вызываем серверную процедуру, передавая адрес «посылки»
ПрочитатьФайлНаСервере(АдресХранилища, ФайлНаКлиенте.Расширение);
КонецПроцедуры
Теперь, когда файл находится в памяти сервера (в хранилище), мы можем с ним работать. Рассмотрим, как прочитать данные из Excel, не используя установленный Microsoft Office. Мы воспользуемся объектом ТабличныйДокумент, который умеет нативно открывать файлы форматов .xls и .xlsx.
&НаСервере
Процедура ПрочитатьФайлНаСервере(АдресХранилища, РасширениеФайла)
// Извлекаем двоичные данные из хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
// Создаем временный файл на диске сервера, чтобы ТабличныйДокумент мог его прочитать
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(РасширениеФайла);
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабДок = Новый ТабличныйДокумент;
Попытка
// Читаем файл. Параметр «Значение» позволяет 1С автоматически определять типы (число, дата)
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Ошибка при чтении файла: " + ОписаниеОшибки());
УдалитьФайлы(ИмяВременногоФайла);
Возврат;
КонецПопытки;
// Теперь перебираем строки табличного документа
КоличествоСтрок = ТабДок.ВысотаТаблицы;
Для НомерСтроки = 1 По КоличествоСтрок Цикл
// Например, читаем Артикул из первой колонки и Цену из второй
Артикул = ТабДок.Область(НомерСтроки, 1).Текст;
Цена = ТабДок.Область(НомерСтроки, 2).Значение;
// Здесь должна быть ваша логика поиска товара и записи данных
// ...
КонецЦикла;
// Обязательно подметаем за собой временные файлы
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Рассмотрим преимущества использования ТабличныйДокумент.Прочитать():
.xlsx платформой происходит в разы быстрее, чем последовательное обращение к каждой ячейке через COM-интерфейс Excel.COMОбъект часто блокируется настройками безопасности Windows (ошибки инициализации, отсутствие доступа к папке Desktop в системных профилях).Проанализируем еще несколько важных моментов, которые сделают вашу загрузку профессиональной:
Асинхронность: В последних версиях платформы (8.3.15+) компания 1С рекомендует отказываться от синхронных вызовов. Вместо Диалог.Выбрать() и ПоместитьВоВременноеХранилище() лучше использовать метод НачатьПомещениеФайлаНаСервер(). Это позволит избежать блокировки интерфейса браузера во время загрузки тяжелых файлов.
Очистка памяти: Если файл Excel очень большой (сотни тысяч строк), ТабличныйДокумент может занять значительный объем оперативной памяти на сервере. В таких ситуациях после прочтения данных в таблицу значений или массив, сразу очищайте переменную ТабДок = Неопределено;.
Тип данных: При использовании СпособЧтенияЗначенийТабличногоДокумента.Текст вы получите данные ровно в том виде, в котором они видны в Excel (со всеми пробелами-разделителями в числах). Если вам нужны чистые числа для расчетов, используйте СпособЧтенияЗначенийТабличногоДокумента.Значение.
Таким образом, мы выяснили, что ключ к стабильной загрузке из Excel в веб-среде — это отделение этапа выбора файла от этапа обработки и использование встроенных механизмов 1С для работы с табличными форматами.