При переносе программного кода, работающего с файловой системой, из файловой базы или обычного клиента на сторону сервера 1С:Предприятия разработчики часто сталкиваются с тем, что проверенные методы начинают работать некорректно. Самая распространенная проблема — метод Существует() объекта Файл упорно возвращает Ложь, хотя файл гарантированно находится по указанному пути. Другая частая проблема — некорректная запись полученного размера файла в базу данных (например, когда число «схлопывается» до 99).
В этой статье мы подробно разберем, как правильно организовать работу с файлами на стороне сервера приложений, почему сетевые диски «не видны» серверу 1С, как решить проблемы с правами доступа ОС и как правильно сохранять размер файлов в метаданных.
Когда вы запускаете обработку на клиенте, код выполняется в контексте вашей учетной записи Windows. У вас могут быть подключены сетевые диски (например, диск K:\), и операционная система прозрачно авторизует ваши запросы к сетевым хранилищам. Но как только этот же код переносится на сервер приложений 1С (в серверный модуль или фоновое задание), контекст выполнения кардинально меняется.
Проанализируем две ключевые причины, почему сервер не видит файлы по сетевым путям:
K:\ для сервера 1С просто не существует. Решением является обязательное использование полных сетевых путей в формате UNC: \\имя_сервера\имя_папки\имя_файла вместо букв дисков.USR1CV8. Этот пользователь не имеет доступа к сетевым ресурсам других серверов и компьютеров в домене. Платформа честно возвращает Ложь при попытке проверить существование файла, так как у процесса просто нет прав зайти в эту папку.Разберем по шагам, как правильно преобразовать путь к файлу в коде и настроить права доступа.
Если в вашей базе хранятся пути с использованием локальных букв дисков, их необходимо динамически заменять на сетевые аналоги при выполнении кода на сервере. Рассмотрим пример кода:
// Неправильно для сервера: "K:\Bases\1Cv8.1CD"
// Правильно для сервера: "\\srv-sql\Bases\1Cv8.1CD"
ПутьКБазе = ВыборкаДетальныеЗаписи.ПутьКБазе;
ИмяФайла = СокрЛП(ПутьКБазе) + "1Cv8.1CD";
// Если код выполняется на сервере, заменяем букву диска на сетевой UNC-путь
Если НаСервере() Тогда
ИмяФайла = СтрЗаменить(ИмяФайла, "K:\", "\\srv-sql\shared_folder\");
КонецЕсли;
ВыбФайл = Новый Файл(ИмяФайла);
Если ВыбФайл.Существует() Тогда
РазмерФайла = ВыбФайл.Размер();
КонецЕсли;
Для того чтобы сервер приложений мог беспрепятственно читать файлы по сети, системному администратору необходимо выполнить одну из следующих настроек:
services.msc) с локального пользователя USR1CV8 на доменную учетную запись (например, DOMAIN\Srv1C). После этого именно этой доменной записи необходимо предоставить права доступа («Чтение» и «Просмотр содержимого папки») на сетевом ресурсе, где лежат целевые файлы.USR1CV8 и абсолютно таким же паролем, как и на сервере 1С. Предоставить этому пользователю доступ к общей папке. Windows автоматически авторизует сетевой запрос по совпадению пары логин/пароль.В процессе обсуждения авторы заметили странный эффект: если перед проверкой существования файла инициировать COM-подключение через V83.ComConnector, то файлы некоторых баз чудесным образом начинают определяться методом Существует() как истинные, а без подключения — нет.
Выясним причину этого феномена. Дело в механизме кэширования сетевых сессий Windows (SMB Session Caching):
V83.ComConnector пытается подключиться к базе, он выполняет авторизацию в сетевой папке, используя учетные данные или настройки гостевого доступа.rphost), последующие стандартные вызовы файловой системы через объект Файл используют это уже установленное доверенное подключение.Важно помнить: использовать создание тяжелого COM-объекта только ради того, чтобы «пробить» сетевой доступ к файлу — это крайне неоптимальный и грубый подход. Это приводит к утечкам памяти, блокировкам файлов (созданию файлов 1Cv8.1CL) и непредсказуемому поведению системы. Решать проблему нужно исключительно настройкой прав Windows на уровне сетевых папок!
Среди разработчиков часто возникают споры о том, как правильнее проверять наличие файлов и их свойства. Некоторые утверждают, что использовать конструктор Новый Файл() — некорректно, и нужно использовать функцию НайтиФайлы(). Проанализируем эту ситуацию.
На самом деле, оба метода абсолютно легитимны, но они решают разные задачи:
Новый Файл(Путь) — это самый быстрый способ получить доступ к свойствам конкретного файла, если его точное имя и путь уже известны. Метод создает объект-ссылку. Обращение к физическому файлу происходит только в момент вызова методов Существует() или Размер().НайтиФайлы(Путь, Маска) — незаменим, когда точное имя файла неизвестно или требуется найти файлы по маске (например, все файлы с расширением *.1CD). Также этот метод крайне полезен при работе на серверах под управлением ОС Linux, где файловая система чувствительна к регистру символов (case-sensitive). На Linux файл 1Cv8.1CD и 1cv8.1cd — это два разных файла. Поиск файлов по маске помогает обойти это ограничение.Пример безопасного получения размера файла с обработкой возможных исключений:
Функция ПолучитьРазмерФайлаБезопасно(ПолныйПуть) Экспорт
РезультирующийРазмер = 0;
ФайловыйОбъект = Новый Файл(ПолныйПуть);
Попытка
Если ФайловыйОбъект.Существует() Тогда
РезультирующийРазмер = ФайловыйОбъект.Размер();
Иначе
ЗаписьЖурналаРегистрации("Работа с файлами",
УровеньЖурналаРегистрации.Предупреждение,
, ,
"Файл не найден по пути: " + ПолныйПуть);
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("Работа с файлами",
УровеньЖурналаРегистрации.Ошибка,
, ,
"Ошибка доступа к файлу: " + ОписаниеОшибки());
КонецПопытки;
Возвращать РезультирующийРазмер;
КонецФункции
Рассмотрим еще одну распространенную техническую ошибку. Разработчик пытается выгрузить корректно определенный размер файла в табличную часть обработки или документа, однако вместо реального объема (например, 150 240 байт) на экране и в базе отображается число 99.
Причина кроется в ограничении длины числового типа данных в метаданных конфигурации:
Число с длиной 2 и точностью 0.99.Решение проблемы:
15 знаков с точностью 0. Это позволит корректно сохранять размеры файлов в байтах вплоть до терабайтных значений.2 знака после запятой.Пример перевода байтов в мегабайты для записи в реквизит с точностью до двух знаков:
РазмерВБайтах = ВыбФайл.Размер(); // Например, 15728640 байт
РазмерВМегабайтах = Окр(РазмерВБайтах / (1024 * 1024), 2); // Результат: 15.00 Мб
СтрокаТЧ = Объект.ТабличнаяЧастьФайлов.Добавить();
СтрокаТЧ.ИмяФайла = ВыбФайл.Имя;
СтрокаТЧ.РазмерМБ = РазмерВМегабайтах; // Теперь число поместится корректно
Придерживаясь этих простых правил настройки сетевого окружения и работы с метаданными в 1С, вы сможете избежать неявных ошибок доступа и обеспечите стабильную работу серверного кода при взаимодействии с файловой системой.