Каждый разработчик 1С рано или поздно сталкивается с классической проблемой клиент-серверной архитектуры: код, который идеально работает на компьютере пользователя (на клиенте), внезапно выдает критическую ошибку при попытке выполнить его на сервере. Особенно часто это происходит при работе с внешними файлами, например, при вызове метода ЧтениеXML.ОткрытьФайл.
Типичный сценарий: вы пытаетесь прочитать XML-документ, расположенный по сетевому пути (например, \\Flserver\файловый_сервер\Прочие\057_от_31_01_2020.xml), но система возвращает ошибку:
«Ошибка при выполнении файловой операции... по причине: Ошибка доступа к файлу»
При этом, если вы попытаетесь открыть этот же файл интерактивно через меню «Файл — Открыть» в самом клиенте 1С, он откроется без каких-либо проблем. Давайте подробно разберем, почему так происходит, проанализируем архитектурные причины этой ошибки и рассмотрим все возможные способы её решения — от администрирования операционной системы до чисто программных методов обхода.
Основная причина кроется в разнице контекстов безопасности (прав доступа) пользователя Windows и службы 1С. Разберем эту ситуацию по шагам:
DOMAIN\Иван_Иванов). У вашей учетной записи есть все необходимые права на чтение и запись в сетевую папку \\Flserver\файловый_сервер\. Соответственно, файл открывается успешно.USR1CV8.USR1CV8) не существует для удаленного файлового сервера Flserver. У него нет сетевого удостоверения. Соответственно, когда сервер 1С пытается обратиться по сетевому пути к файлу, операционная система файлового сервера блокирует этот запрос, возвращая ошибку доступа.Ниже мы подробно рассмотрим несколько способов решения этой проблемы.
Если вам жизненно важно, чтобы сервер 1С читал файлы напрямую из сетевой папки общего доступа, необходимо правильно настроить авторизацию службы в локальной сети.
Вариант А. Если в вашей организации развернут домен (Active Directory):
DOMAIN\usr1cv8_service).services.msc).DOMAIN\usr1cv8_service и введите его пароль. Сохраните изменения и перезапустите службу.Flserver, откройте свойства сетевой папки, вкладку «Безопасность» (Security) и предоставьте доменному пользователю DOMAIN\usr1cv8_service полные права (или как минимум права на чтение и изменение) на эту папку и вложенные файлы.Вариант Б. Если домен отсутствует (рабочая группа):
Flserver создайте абсолютно одинаковых локальных пользователей (с полностью совпадающими именами и паролями, например, пользователь SyncUser1C с паролем SuperPassword123).SyncUser1C полные права на сетевую папку.Разрешить сетевой доступ на уровне операционной системы удается не всегда — часто мешают жесткие политики безопасности компании или особенности ИТ-инфраструктуры. В этом случае на помощь приходит чисто программный метод 1С, который позволяет полностью исключить зависимость сервера от сетевых прав.
Идея проста: мы считываем файл на клиенте (где у текущего пользователя точно есть права на сетевую папку), помещаем его во временное хранилище платформы, передаем адрес хранилища на сервер, извлекаем двоичные данные на сервере, сохраняем их во временный файл локальной ОС сервера и спокойно открываем его через ЧтениеXML.
Рассмотрим, как это реализовать на практике с помощью кода:
&НаКлиенте
Процедура ПрочитатьФайлXMLНаКлиенте()
// Определяем путь к нашему сетевому файлу
ПутьКФайлу = "\\Flserver\файловый_сервер\Прочие\057_от_31_01_2020.xml";
// Проверяем существование файла на клиенте
ФайлНаДиске = Новый Файл(ПутьКФайлу);
Если Не ФайлНаДиске.Существует() Тогда
Предупреждение("Файл не найден по указанному пути!");
Возврат;
КонецЕсли;
// Помещаем файл в двоичные данные и отправляем во временное хранилище
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
// Вызываем серверную процедуру для обработки файла
ОбработатьФайлНаСервере(АдресХранилища);
КонецПроцедуры
Теперь напишем серверную часть, которая примет адрес временного хранилища, запишет файл на локальный диск сервера (где у службы 1С гарантированно есть полные права доступа во временную папку операционной системы) и выполнит чтение:
&НаСервереБезКонтекста
Процедура ОбработатьФайлНаСервере(Знач АдресХранилища)
// Получаем двоичные данные из временного хранилища
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
// Создаем имя для временного файла на сервере
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
// Записываем двоичные данные в локальный файл на сервере
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
// Инициализируем объект ЧтениеXML
ЧтениеXML = Новый ЧтениеXML;
Попытка
// Теперь файл локальный для сервера, никаких сетевых ошибок не возникнет
ЧтениеXML.ОткрытьФайл(ИмяВременногоФайла);
// Начинаем чтение и разбор XML структуры
Пока ЧтениеXML.Прочитать() Цикл
// Реализуйте здесь вашу логику разбора XML
// Например:
// Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// ИмяУзла = ЧтениеXML.Имя;
// КонецЕсли;
КонецЦикла;
// Обязательно закрываем файл после чтения!
ЧтениеXML.Закрыть();
Исключение
// В случае ошибки гарантируем закрытие файла и генерацию исключения
Если ЧтениеXML <> Неопределено Тогда
ЧтениеXML.Закрыть();
КонецЕсли;
// Удаляем временный файл, чтобы не засорять диск сервера
УдалитьФайлы(ИмяВременногоФайла);
ВызватьИсключение КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
// Удаляем временный файл после успешного завершения операции
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Если обрабатываемый XML-файл имеет небольшой или средний объем (до нескольких мегабайт), мы можем полностью отказаться от создания каких-либо временных файлов на жестком диске сервера. Мы можем прочитать весь XML-файл в текстовую строку на клиенте, передать эту строку на сервер и скормить её объекту ЧтениеXML напрямую через оперативную память.
Давайте проанализируем этот элегантный способ:
&НаКлиенте
Процедура ПрочитатьXMLЧерезСтроку()
ПутьКФайлу = "\\Flserver\файловый_сервер\Прочие\057_от_31_01_2020.xml";
// Читаем весь файл в строку на клиенте
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ПутьКФайлу, КодировкаТекста.UTF8);
СтрокаXML = ТекстовыйДокумент.ПолучитьТекст();
// Передаем строку на сервер для разбора
РазбратьСтрокуXMLНаСервере(СтрокаXML);
КонецПроцедуры
На сервере мы инициализируем объект ЧтениеXML не через метод ОткрытьФайл, а с помощью метода УстановитьСтроку:
&НаСервереБезКонтекста
Процедура РазбратьСтрокуXMLНаСервере(СтрокаXML)
ЧтениеXML = Новый ЧтениеXML;
Попытка
// Загружаем XML-данные напрямую из строковой переменной
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Пока ЧтениеXML.Прочитать() Цикл
// Обработка узлов XML документа в памяти
КонецЦикла;
ЧтениеXML.Закрыть();
Исключение
Если ЧтениеXML <> Неопределено Тогда
ЧтениеXML.Закрыть();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Этот способ работает чрезвычайно быстро, так как полностью исключает дисковые операции ввода-вывода (I/O) на стороне сервера, и решает проблему сетевого доступа на 100%.
Все чаще серверная часть 1С разворачивается под управлением операционных систем семейства Linux. В этом случае попытка открыть сетевой путь в формате Windows UNC (например, начинающийся с двойного слэша \\Flserver\...) на сервере завершится ошибкой в любом случае, даже если вы пропишете все возможные права. ОС Linux просто не понимает такой синтаксис путей.
Как решить проблему на Linux-сервере:
mount. Пример команды монтирования сетевой папки Samba/Windows в каталог сервера Linux:
mount -t cifs -o username=usr1cv8,password=password //Flserver/файловый_сервер /mnt/share_folder
/mnt/share_folder/Прочие/057_от_31_01_2020.xml
Если же вы используете Решение 2 (с временным хранилищем) или Решение 3 (с передачей строки), то кроссплатформенность будет поддерживаться автоматически без какого-либо вмешательства системных администраторов, поскольку платформа 1С сама корректно работает со своими временными каталогами на любой операционной системе.
Иногда ошибка доступа к файлу возникает не из-за отсутствия прав у пользователя или службы, а по причине того, что файл физически заблокирован другим процессом в операционной системе. Например, если внешняя программа-источник в данный момент времени продолжает записывать данные в этот файл XML, или сетевой антивирус начал сканирование только что созданного документа.
Для проверки этой гипотезы можно использовать бесплатную системную утилиту Process Explorer (от Sysinternals) на файловом сервере. С её помощью через меню «Find — Find Handle or DLL» можно легко найти, какой именно процесс (PID) держит дескриптор проблемного файла, и при необходимости завершить эту операцию.
Мы подробно проанализировали проблему работы метода ЧтениеXML.ОткрытьФайл в клиент-серверной архитектуре 1С. Подведем итоги: