Почему не работает ЧтениеXML.ОткрытьФайл в 1С и как решить проблему доступа к файлу

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

Каждый разработчик 1С рано или поздно сталкивается с классической проблемой клиент-серверной архитектуры: код, который идеально работает на компьютере пользователя (на клиенте), внезапно выдает критическую ошибку при попытке выполнить его на сервере. Особенно часто это происходит при работе с внешними файлами, например, при вызове метода ЧтениеXML.ОткрытьФайл.

Типичный сценарий: вы пытаетесь прочитать XML-документ, расположенный по сетевому пути (например, \\Flserver\файловый_сервер\Прочие\057_от_31_01_2020.xml), но система возвращает ошибку:

«Ошибка при выполнении файловой операции... по причине: Ошибка доступа к файлу»

При этом, если вы попытаетесь открыть этот же файл интерактивно через меню «Файл — Открыть» в самом клиенте 1С, он откроется без каких-либо проблем. Давайте подробно разберем, почему так происходит, проанализируем архитектурные причины этой ошибки и рассмотрим все возможные способы её решения — от администрирования операционной системы до чисто программных методов обхода.

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

Основная причина кроется в разнице контекстов безопасности (прав доступа) пользователя Windows и службы 1С. Разберем эту ситуацию по шагам:

  1. Контекст клиента: Когда вы запускаете 1С и выполняете код на стороне клиента, программа работает под правами вашей текущей учетной записи Windows (например, DOMAIN\Иван_Иванов). У вашей учетной записи есть все необходимые права на чтение и запись в сетевую папку \\Flserver\файловый_сервер\. Соответственно, файл открывается успешно.
  2. Контекст сервера: Когда управление передается на сервер (например, при вызове серверной процедуры, выполнении фонового или регламентного задания), код выполняется от имени пользователя ОС, под которым запущена Windows-служба «Агент сервера 1С:Предприятия». По умолчанию при установке платформы создается локальный пользователь USR1CV8.
  3. Проблема сетевой авторизации: Локальный пользователь сервера 1С (USR1CV8) не существует для удаленного файлового сервера Flserver. У него нет сетевого удостоверения. Соответственно, когда сервер 1С пытается обратиться по сетевому пути к файлу, операционная система файлового сервера блокирует этот запрос, возвращая ошибку доступа.

Ниже мы подробно рассмотрим несколько способов решения этой проблемы.

Решение 1. Настройка сетевых прав для службы Агента сервера 1С

Если вам жизненно важно, чтобы сервер 1С читал файлы напрямую из сетевой папки общего доступа, необходимо правильно настроить авторизацию службы в локальной сети.

Вариант А. Если в вашей организации развернут домен (Active Directory):

  1. Создайте в домене специальную сервисную учетную запись (например, DOMAIN\usr1cv8_service).
  2. Откройте на сервере 1С консоль управления службами (выполните команду services.msc).
  3. Найдите в списке службу «Агент сервера 1С:Предприятия», откройте её свойства и перейдите на вкладку «Вход в систему» (Log On).
  4. Переключите переключатель в положение «С учетной записью», укажите созданного доменного пользователя DOMAIN\usr1cv8_service и введите его пароль. Сохраните изменения и перезапустите службу.
  5. Перейдите на файловый сервер Flserver, откройте свойства сетевой папки, вкладку «Безопасность» (Security) и предоставьте доменному пользователю DOMAIN\usr1cv8_service полные права (или как минимум права на чтение и изменение) на эту папку и вложенные файлы.

Вариант Б. Если домен отсутствует (рабочая группа):

  1. На сервере 1С и на файловом сервере Flserver создайте абсолютно одинаковых локальных пользователей (с полностью совпадающими именами и паролями, например, пользователь SyncUser1C с паролем SuperPassword123).
  2. Настройте запуск службы Агента сервера 1С под этим локальным пользователем.
  3. На файловом сервере предоставьте созданному пользователю SyncUser1C полные права на сетевую папку.

Решение 2. Обход проблемы с помощью Временного хранилища (Рекомендуемый способ)

Разрешить сетевой доступ на уровне операционной системы удается не всегда — часто мешают жесткие политики безопасности компании или особенности ИТ-инфраструктуры. В этом случае на помощь приходит чисто программный метод 1С, который позволяет полностью исключить зависимость сервера от сетевых прав.

Идея проста: мы считываем файл на клиенте (где у текущего пользователя точно есть права на сетевую папку), помещаем его во временное хранилище платформы, передаем адрес хранилища на сервер, извлекаем двоичные данные на сервере, сохраняем их во временный файл локальной ОС сервера и спокойно открываем его через ЧтениеXML.

Рассмотрим, как это реализовать на практике с помощью кода:


&НаКлиенте
Процедура ПрочитатьФайлXMLНаКлиенте()
    
    // Определяем путь к нашему сетевому файлу
    ПутьКФайлу = "\\Flserver\файловый_сервер\Прочие\057_от_31_01_2020.xml";
    
    // Проверяем существование файла на клиенте
    ФайлНаДиске = Новый Файл(ПутьКФайлу);
    Если Не ФайлНаДиске.Существует() Тогда
        Предупреждение("Файл не найден по указанному пути!");
        Возврат;
    КонецЕсли;
    
    // Помещаем файл в двоичные данные и отправляем во временное хранилище
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
    АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
    
    // Вызываем серверную процедуру для обработки файла
    ОбработатьФайлНаСервере(АдресХранилища);
    
КонецПроцедуры

Теперь напишем серверную часть, которая примет адрес временного хранилища, запишет файл на локальный диск сервера (где у службы 1С гарантированно есть полные права доступа во временную папку операционной системы) и выполнит чтение:


&НаСервереБезКонтекста
Процедура ОбработатьФайлНаСервере(Знач АдресХранилища)
    
    // Получаем двоичные данные из временного хранилища
    ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    // Создаем имя для временного файла на сервере
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
    
    // Записываем двоичные данные в локальный файл на сервере
    ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
    
    // Инициализируем объект ЧтениеXML
    ЧтениеXML = Новый ЧтениеXML;
    
    Попытка
        // Теперь файл локальный для сервера, никаких сетевых ошибок не возникнет
        ЧтениеXML.ОткрытьФайл(ИмяВременногоФайла);
        
        // Начинаем чтение и разбор XML структуры
        Пока ЧтениеXML.Прочитать() Цикл
            // Реализуйте здесь вашу логику разбора XML
            // Например:
            // Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            //     ИмяУзла = ЧтениеXML.Имя;
            // КонецЕсли;
        КонецЦикла;
        
        // Обязательно закрываем файл после чтения!
        ЧтениеXML.Закрыть();
        
    Исключение
        // В случае ошибки гарантируем закрытие файла и генерацию исключения
        Если ЧтениеXML <> Неопределено Тогда
            ЧтениеXML.Закрыть();
        КонецЕсли;
        
        // Удаляем временный файл, чтобы не засорять диск сервера
        УдалитьФайлы(ИмяВременногоФайла);
        
        ВызватьИсключение КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
    // Удаляем временный файл после успешного завершения операции
    УдалитьФайлы(ИмяВременногоФайла);
    
КонецПроцедуры

Решение 3. Чтение небольших файлов 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%.

Решение 4. Особенности кроссплатформенности (Если сервер 1С работает на Linux)

Все чаще серверная часть 1С разворачивается под управлением операционных систем семейства Linux. В этом случае попытка открыть сетевой путь в формате Windows UNC (например, начинающийся с двойного слэша \\Flserver\...) на сервере завершится ошибкой в любом случае, даже если вы пропишете все возможные права. ОС Linux просто не понимает такой синтаксис путей.

Как решить проблему на Linux-сервере:

  1. Сетевую папку с файлового сервера Windows необходимо предварительно примонтировать в файловую систему Linux-сервера. Для этого системный администратор должен использовать утилиту mount. Пример команды монтирования сетевой папки Samba/Windows в каталог сервера Linux:

    mount -t cifs -o username=usr1cv8,password=password //Flserver/файловый_сервер /mnt/share_folder

  2. В коде 1С, выполняющемся на сервере, путь к файлу должен указываться в формате Linux:

    /mnt/share_folder/Прочие/057_от_31_01_2020.xml

Если же вы используете Решение 2 (с временным хранилищем) или Решение 3 (с передачей строки), то кроссплатформенность будет поддерживаться автоматически без какого-либо вмешательства системных администраторов, поскольку платформа 1С сама корректно работает со своими временными каталогами на любой операционной системе.

Решение 5. Исключение монопольной блокировки файла

Иногда ошибка доступа к файлу возникает не из-за отсутствия прав у пользователя или службы, а по причине того, что файл физически заблокирован другим процессом в операционной системе. Например, если внешняя программа-источник в данный момент времени продолжает записывать данные в этот файл XML, или сетевой антивирус начал сканирование только что созданного документа.

Для проверки этой гипотезы можно использовать бесплатную системную утилиту Process Explorer (от Sysinternals) на файловом сервере. С её помощью через меню «Find — Find Handle or DLL» можно легко найти, какой именно процесс (PID) держит дескриптор проблемного файла, и при необходимости завершить эту операцию.

Резюме

Мы подробно проанализировали проблему работы метода ЧтениеXML.ОткрытьФайл в клиент-серверной архитектуре 1С. Подведем итоги:

← На главную