При работе в клиент-серверном варианте 1С:Предприятие начинающие разработчики часто сталкиваются с ошибкой «Ошибка доступа к файлу» при попытке прочитать данные из Excel. Ситуация обычно выглядит так: файл лежит на рабочем столе пользователя, код выполняется на сервере, и система отказывается видеть путь. В этой статье мы подробно разберем, почему возникает эта проблема, и как правильно реализовать чтение файлов, чтобы избежать ограничений прав доступа.
Проанализируем ситуацию с точки зрения архитектуры 1С. Когда вы запускаете код в процедуре с директивой &НаСервере, исполнителем кода становится не ваш компьютер, а сервер приложений 1С (процесс rphost). Для сервера путь C:\Users\ИмяПользователя\Desktop\файл.xls либо вообще не существует, либо является недоступным, так как у службы сервера нет прав на чтение личных папок пользователей.
Важно понимать следующие моменты:
ТабличныйДокумент.Прочитать() недоступен на стороне тонкого клиента, что вынуждает нас передавать файл на сервер.Рассмотрим самый надежный и правильный способ, который позволяет прочитать файл, где бы он ни находился на компьютере пользователя. Мы не будем заставлять сервер «идти» к файлу, а сами «принесем» файл на сервер.
Алгоритм действий будет следующим: на клиенте мы считываем файл в двоичные данные, помещаем их во временное хранилище, передаем адрес хранилища на сервер, и уже там восстанавливаем файл во временном каталоге сервера для чтения.
Посмотрим на пример реализации кода:
&НаКлиенте
Процедура ПрочитатьФайлExcel(Команда)
// Выбираем файл на клиенте
Диалог = Новый ДиалогВыбора Файла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Excel (*.xls, *.xlsx)|*.xls;*.xlsx";
Если Диалог.Выбрать() Тогда
ПолныйПутьКФайлу = Диалог.ПолныйИмяФайла;
// Читаем файл в двоичные данные на клиенте
ДвоичныеДанные = Новый ДвоичныеДанные(ПолныйПутьКФайлу);
// Помещаем во временное хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
// Вызываем серверную функцию для обработки
Результат = ОбработатьФайлНаСервере(АдресХранилища);
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ОбработатьФайлНаСервере(АдресХранилища)
// Извлекаем данные из хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
// Создаем временное имя файла на стороне сервера
ИмяФайлаНаСервере = ПолучитьИмяВременногоФайла("xlsx");
// Записываем данные в файл на диске сервера
ДвоичныеДанные.Записать(ИмяФайлаНаСервере);
ТабДок = Новый ТабличныйДокумент;
Попытка
// Теперь сервер читает СВОЙ локальный временный файл
ТабДок.Прочитать(ИмяФайлаНаСервере, СпособЧтенияЗначенийТабличногоДокумента.Текст);
// Удаляем временный файл после чтения (хороший тон)
УдалитьФайлы(ИмяФайлаНаСервере);
Исключение
Сообщить("Ошибка при чтении файла на сервере: " + ОписаниеОшибки());
Возврат Ложь;
КонецПопытки;
// Далее идет логика обхода ТабличногоДокумента
// ...
Возврат Истина;
КонецФункции
В этом примере мы используем объект ДвоичныеДанные, который выступает контейнером для передачи содержимого файла. Функция ПолучитьИмяВременногоФайла() гарантирует, что мы создаем файл в папке, к которой у сервера 1С точно есть права на запись и чтение.
Если по каким-то причинам вы все же хотите использовать прямые пути (например, при автоматической загрузке по расписанию), необходимо проанализировать настройки службы Windows. Выясним причину блокировки доступа:
Проанализируем программные особенности методов платформы 1С. При использовании ТабличныйДокумент.Прочитать() важно помнить:
.xlsx (Excel 2007+) встроенными средствами. Это значит, что наличие установленного Microsoft Office на сервере не требуется..xlsx перед обработкой.При сверке номенклатуры (как в случае автора вопроса) чтение файла — это только половина дела. Выясним, как правильно сопоставлять данные. Использование только наименования — плохая практика, так как могут быть дубли или лишние пробелы.
Рекомендация: При выгрузке данных в Excel всегда добавляйте колонку с уникальным идентификатором (GUID) ссылки 1С. При обратном чтении используйте метод Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(ЗначениеИзФайла)). Это позволит однозначно найти элемент в базе, даже если его наименование изменилось.
Рассмотрим еще пару важных моментов:
Во-первых, при работе с очень большими файлами ТабличныйДокумент может потреблять много оперативной памяти. Если ваш файл содержит десятки тысяч строк, рассмотрите возможность использования объекта ЧтениеXML для прямого парсинга структуры .xlsx (который по сути является архивом XML-файлов).
Во-вторых, всегда используйте блоки Попытка...Исключение вокруг метода Прочитать(). Это позволит корректно обработать ситуацию, если файл поврежден или имеет неверный формат, не прерывая работу всей программы.
Соблюдение этих правил и использование схемы с временным хранилищем сделает вашу обработку надежной и независимой от настроек конкретного рабочего места пользователя.