При разработке и администрировании систем на базе платформы 1С:Предприятие в клиент-серверном режиме разработчики часто сталкиваются с загадочным поведением системы. Код, который годами успешно работал на локальном компьютере или на сервере под управлением Windows, внезапно начинает выдавать ошибки при переносе на Linux-сервер. Типичный сценарий: при попытке прочитать или записать файл система сообщает об ошибке, при этом в тексте ошибки путь к файлу выглядит странно — все привычные обратные слэши (\) оказываются замененными на прямые (/), например: Файл не обнаружен 'C:/1.mxl'. Разберем подробно, почему так происходит, как устроена кроссплатформенная работа с файловой системой в 1С и как правильно решить эту проблему раз и навсегда.
Для начала проанализируем внутреннее поведение платформы 1С. Платформа является полностью кроссплатформенным решением, способным работать как в операционных системах семейства Windows, так и в UNIX-подобных системах (Linux). В этих операционных системах принципиально по-разному реализована работа с путями файловой системы:
\), а структура файлов привязана к дискам с буквенными обозначениями (например, C:\Папка\Файл.txt). Также поддерживаются сетевые UNC-пути вида \\ИмяКомпьютера\Ресурс\Файл.txt./). Понятия «буква диска» в Linux не существует — файловая система представляет собой единое дерево, начинающееся с корневого каталога (/), к которому монтируются физические диски и сетевые ресурсы (например, /media/share/file.txt).Когда серверная часть 1С запущена под управлением ОС Linux, все файловые операции, выполняемые в серверном контексте (на сервере), обрабатываются операционной системой Linux. Разработчики платформы 1С заложили в нее механизм автоматической нормализации путей. Платформа пытается привести любой переданный ей путь к стандарту той операционной системы, под управлением которой выполняется текущий рабочий процесс 1С.
Если сервер 1С работает на Linux, любой переданный ему путь (даже если он жестко прописан в коде с обратными слэшами) автоматически преобразуется платформой под стандарт Linux — то есть все обратные слэши заменяются на прямые. Именно поэтому в тексте ошибки вы видите путь вида C:/1.mxl или //server/share/file.mxl. Платформа просто выводит путь в том формате, в котором его пытается обработать ядро Linux.
Следовательно, проблема заключается вовсе не в том, что 1С «испортила» слэши. Проблема в том, что ОС Linux физически не может получить доступ к диску C:\ или напрямую обратиться к сетевому UNC-пути Windows без предварительной настройки.
Рассмотрим самый надежный, безопасный и правильный с точки зрения архитектуры 1С метод работы с файлами в клиент-серверной архитектуре. Нам не нужно настраивать права доступа операционных систем или монтировать сетевые диски. Вместо этого мы передадим файл с клиента на сервер в виде двоичных данных через механизм временного хранилища 1С.
Посмотрим на практический пример реализации этого подхода по шагам.
Шаг 1. Код на стороне клиента (Windows)
На клиенте мы выбираем файл, преобразуем его в объект ДвоичныеДанные и помещаем во временное хранилище. Полученный уникальный адрес мы передаем на сервер.
&НаКлиенте
Процедура ОтправитьФайлНаСервер()
// Выбираем файл на компьютере пользователя
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Фильтр = "Табличный документ (*.mxl)|*.mxl";
Диалог.МножественныйВыбор = Ложь;
Если Диалог.Выбрать() Тогда
ВыбранныйФайл = Диалог.ПолноеИмяФайла;
// Читаем файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ВыбранныйФайл);
// Помещаем во временное хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификатор);
// Вызываем серверный метод для обработки
ОбработатьФайлНаСервере(АдресХранилища);
КонецЕсли;
КонецПроцедуры
Шаг 2. Код на стороне сервера (Linux)
На сервере мы получаем двоичные данные из хранилища. Чтобы прочитать файл (например, табличный документ), нам нужно записать его во временную папку на сервере. Для этого мы запрашиваем у платформы путь к временному каталогу сервера, который гарантированно существует и доступен для записи процессу 1С.
&НаСервере
Процедура ОбработатьФайлНаСервере(Знач АдресХранилища)
// Получаем двоичные данные из временного хранилища
ДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ДанныеФайла = Неопределено Тогда
ВызватьИсключение "Не удалось получить данные из временного хранилища.";
КонецЕсли;
// Получаем уникальное имя временного файла на сервере с нужным расширением
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("mxl");
// Записываем данные во временный файл на сервере
ДанныеФайла.Записать(ИмяВременногоФайла);
// Теперь мы можем безопасно работать с файлом средствами 1С
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ИмяВременногоФайла);
// Выполняем необходимую обработку табличного документа...
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Файл успешно прочитан на сервере!");
Исключение
ЗаписьЖурналаРегистрации("ЧтениеФайла", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Ошибка при чтении табличного документа на сервере.";
Конецесли;
// Обязательно удаляем временный файл после завершения работы
Попытка
УдалитьФайлы(ИмяВременногоФайла);
Исключение
// Ошибка удаления временного файла не должна прерывать работу пользователя
ЗаписьЖурналаРегистрации("УдалениеФайла", УровеньЖурналаРегистрации.Предупреждение,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Этот способ полностью исключает любые проблемы со слэшами, правами доступа к дискам или сетевым окружением, так как передача данных происходит по защищенному каналу связи самого сервера 1С.
Если бизнес-логика требует, чтобы сервер 1С напрямую читал файлы из общей сетевой папки Windows (UNC-путь), то нам придется настроить интеграцию на уровне операционных систем. Напрямую обратиться к пути вида \\СетевоеИмяКлиента\Папка сервер на Linux не сможет. Нам нужно «примонтировать» этот сетевой ресурс в дерево каталогов Linux.
Проанализируем этот процесс по шагам.
Шаг 1. Подготовка папки монтирования на сервере Linux
Сначала системный администратор должен создать пустую директорию в Linux, которая будет служить точкой доступа к сетевой папке. Например, создадим каталог /mnt/winshare:
sudo mkdir -p /mnt/winshare
Шаг 2. Монтирование сетевого ресурса по протоколу CIFS/Samba
Для подключения папки используется утилита монтирования. При этом критически важно передать параметры прав доступа, чтобы служба сервера 1С (которая обычно работает под пользователем usr1cv8) имела права на чтение и запись в эту папку.
Выполним команду монтирования:
sudo mount -t cifs //192.168.0.100/SharedFolder /mnt/winshare -o username=WinUser,password=WinPassword,uid=usr1cv8,gid=grp1cv8,iocharset=utf8
Разберем параметры этой команды:
-t cifs — указывает тип файловой системы (сетевой протокол SMB/CIFS, используемый в Windows).//192.168.0.100/SharedFolder — сетевой адрес общей папки Windows. Рекомендуется использовать IP-адрес вместо сетевого имени во избежание проблем с DNS-резолвингом в Linux./mnt/winshare — локальная точка монтирования в Linux.username, password — учетные данные пользователя Windows, у которого есть права на доступ к этой папке.uid=usr1cv8, gid=grp1cv8 — параметры, которые сопоставляют владельца смонтированных файлов с пользователем и группой, под которыми запущен рабочий процесс сервера 1С. Без этих параметров Linux смонтирует папку от имени root, и сервер 1С получит ошибку отсутствия прав доступа.Шаг 3. Обращение к файлу в коде 1С
После успешного монтирования на уровне ОС, в коде 1С на сервере мы обращаемся к файлу как к обычному локальному файлу Linux, используя прямые слэши:
&НаСервере
Процедура ПрочитатьФайлИзСетевойПапки()
ПутьКФайлу = "/mnt/winshare/1.mxl";
// Проверим существование файла перед чтением
ФайлНаДиске = Новый Файл(ПутьКФайлу);
Если ФайлНаДиске.Существует() Тогда
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ПутьКФайлу);
// Обрабатываем документ...
Иначе
ВызватьИсключение "Файл по пути " + ПутьКФайлу + " не найден на сервере Linux.";
КонецЕсли;
КонецПроцедуры
Если вы хотите написать универсальный код, который будет корректно определять пути и работать как на Windows-сервере, так и на Linux-сервере, никогда не используйте жестко заданные символы слэшей в строках путей.
Для решения этой задачи в глобальном контексте 1С предусмотрены специальные системные функции:
ПолучитьРазделительПути() — возвращает разделитель путей файловой системы для текущего сеанса (где выполняется код).ПолучитьРазделительПутиСервера() — возвращает разделитель, используемый на сервере 1С.ПолучитьРазделительПутиКлиента() — возвращает разделитель, используемый на клиенте.Рассмотрим пример динамического построения путей:
&НаСервереБезКонтекста
Функция СформироватьПутьКФайлу(ИмяКаталога, ИмяФайла)
Разделитель = ПолучитьРазделительПутиСервера();
// Собираем путь динамически, избегая ручного ввода слэшей
ПолныйПуть = ИмяКаталога;
Если Не Прав(ПолныйПуть, 1) = Разделитель Тогда
ПолныйПуть = ПолныйПуть + Разделитель;
КонецЕсли;
Возврат ПолныйПуть + ИмяФайла;
КонецФункции
Применение этого метода гарантирует, что при выполнении кода на Windows разделителем станет обратный слэш (\), а на Linux — прямой слэш (/), предотвращая возникновение синтаксических ошибок операционной системы.
Если вы настроили монтирование или передачу файлов, но система все равно выдает ошибку, рекомендуем выполнить экспресс-диагностику с помощью метода НайтиФайлы. Это позволит точно определить, видит ли сервер 1С целевой каталог и файлы в нем.
Проанализируем проверочный код:
&НаСервере
Процедура ПроверитьДоступностьКаталога(ПутьККаталогу)
НайденныеФайлы = НайтиФайлы(ПутьККаталогу, "*.*");
Если НайденныеФайлы.Количество() = 0 Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Каталог пуст или недоступен для чтения службой 1С.");
Иначе
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Успешно! Найдено файлов в каталоге: " + НайденныеФайлы.Количество());
КонецЕсли;
КонецПроцедуры
Если метод НайтиФайлы возвращает пустой массив или падает с ошибкой доступа, это явный сигнал системному администратору проверить права системного пользователя usr1cv8 в операционной системе Linux на доступ к смонтированной директории.