Почему возникает ошибка доступа при сохранении табличного документа в Word и как её исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При выгрузке отчетов или печатных форм в файлы форматов Word (DOCX) или Excel разработчики нередко сталкиваются с ошибкой: «Ошибка доступа к файлу... 5(0x00000005): Отказано в доступе». Ситуация часто ставит в тупик тем, что в тестовой файловой базе выгрузка проходит без замечаний, а в клиент-серверном режиме завершается аварийно, даже если текущий пользователь системы 1С обладает полными административными правами.

Проанализируем природу этой ошибки в клиент-серверной архитектуре и разберем архитектурно правильные способы ее устранения.

Выясним причину ошибки: контекст сервера и права службы

Посмотрим на типичный фрагмент кода, приводящий к сбою на стороне сервера:


ТабДок.Записать(ПутьКФайлам + Стр.Контрагент + ".docx", ТипФайлаТабличногоДокумента.DOCX);

Если этот код выполняется внутри серверной процедуры (директива &НаСервере или общий модуль с признаком «Сервер»), в процессе сохранения возникают сразу две ключевые проблемы:

  1. Разница контекстов файловой системы. Путь к каталогу вида C:\Users\Admin2C\Desktop\..., переданный с клиента на сервер, указывает вовсе не на компьютер пользователя. Сервер приложений пытается записать документ на локальный диск самого физического сервера, где папки текущего пользователя может вовсе не существовать. Кроме того, службы Windows изолированы (Session 0 Isolation) и не имеют доступа к пользовательским рабочим столам.
  2. Права учетной записи службы сервера. Серверная часть платформы функционирует в контексте отдельного пользователя операционной системы (по умолчанию это системная учетная запись usr1cv8). Какими бы правами ни обладал интерактивный пользователь в 1С или на своем локальном компьютере, служба кластера серверов 1С ограничена собственными правами NTFS. По умолчанию запись в пользовательские профили C:\Users\ для учетной записи usr1cv8 заблокирована.

Способ 1. Перенос записи файла на сторону клиента

Самое быстрое и распространенное решение — формировать табличный документ на сервере, а саму запись в файл выполнять на клиенте. Клиентское приложение запущено от имени локального пользователя, имеет полный доступ к его рабочему столу и локальным папкам.

Разберем по шагам реализацию этого подхода в управляемой форме. На сервере мы только генерируем данные, а метод Записать() вызываем в процедуре &НаКлиенте:


&НаСервере
Функция СформироватьТабличныйДокументНаСервере()
    ТабДок = Новый ТабличныйДокумент;
    // Заполнение макета и табличного документа данными
    Возврат ТабДок;
КонецФункции

&НаКлиенте
Процедура СохранитьДокументВWord()
    ТабДок = СформироватьТабличныйДокументНаСервере();
    
    // Путь к файлу на компьютере пользователя
    ПолноеИмяФайла = "C:\Users\Admin2C\Desktop\Отчет.docx";
    
    ТабДок.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.DOCX);
    ПоказатьОповещениеПользователя("Успешно", , "Файл сохранен на рабочий стол");
КонецПроцедуры

В этом сценарии ресурсоемкое построение документа выполняется мощностями сервера, а клиент лишь выполняет операцию сохранения готового объекта в локальный файл.

Способ 2. Передача файла через временное хранилище

Если процедура формирования отчета работает в рамках общего сервисного механизма, где документ сразу преобразуется в бинарные данные, правильнее использовать временное хранилище платформы. Рассмотрим этот вариант:

  1. На сервере сохраняем документ во временный каталог операционной системы с помощью метода ПолучитьИмяВременногоФайла(). К этой системной директории у службы сервера гарантированно есть доступ.
  2. Помещаем файл во временное хранилище через метод ПоместитьВоВременноеХранилище().
  3. На клиенте скачиваем файл из хранилища в каталог пользователя.

Посмотрим на пример реализации:


&НаСервере
Функция СформироватьИПоместитьФайлВХранилище()
    ТабДок = Новый ТабличныйДокумент;
    // Заполнение макета
    
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("docx");
    ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.DOCX);
    
    ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
    АдресФайла = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
    
    УдалитьФайлы(ИмяВременногоФайла);
    Возврат АдресФайла;
КонецФункции

&НаКлиенте
Процедура СохранитьЧерезХранилище()
    АдресФайла = СформироватьИПоместитьФайлВХранилище();
    ПутьСохранения = "C:\Users\Admin2C\Desktop\Отчет.docx";
    
    ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
    ДвоичныеДанные.Записать(ПутьСохранения);
КонецПроцедуры

Способ 3. Сохранение на сервере или сетевом ресурсе

Если задача требует сохранения файла именно силами сервера (например, регламентным заданием по расписанию без участия клиентской части), разберем необходимые настройки сетевого окружения и сервера:

  1. Выделенная папка на сервере. Не используйте пути профилей пользователей. Создайте отдельный каталог, например D:\1C_Export\, и в свойствах безопасности NTFS предоставьте учетной записи службы (usr1cv8) права «Изменение» и «Запись».
  2. Сетевые ресурсы. Нельзя использовать подключенные сетевые диски (например, Z:\), поскольку они монтируются в интерактивном сеансе конкретного пользователя и службе сервера не видны. Используйте только прямые UNC-пути: \\server\share\folder\. Для записи на сторонний сервер служба 1С должна запускаться под доменным пользователем, имеющим доступ к целевой сетевой папке.
  3. Профили безопасности кластера. Если в кластере 1С включены профили безопасности, убедитесь, что в профиле информационной базы разрешен доступ к файловой системе для указанного пути.

Важный нюанс: недопустимые символы в имени файла

Обратите внимание на формирование имени файла: если в наименовании контрагента присутствуют кавычки (например, ООО "Электролюкс"), слеши или двоеточия, операционная система Windows вернет ошибку доступа или ошибку неверного синтаксиса имени файла. Перед записью обязательно удаляйте или заменяйте запрещенные знаки / \ : * ? " < > | с помощью функции СтрЗаменить().

← На главную