Как правильно сохранять и читать настройки из файла в клиент-серверной архитектуре 1С?

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

При переходе с обычных форм на управляемые разработчики часто сталкиваются с тем, что привычный код для работы с файлами перестает работать в клиент-серверном варианте базы (на SQL), хотя отлично функционирует в файловом режиме. Давайте подробно разберем эту ситуацию, проанализируем частые ошибки и выясним, как правильно организовать сохранение и чтение настроек.

Анализ проблемы: почему код работает в файловой базе, но падает на сервере?

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


&НаСервере
Процедура ПрочитатьНастройкиИзФайлаНаСервере()
    Объект.СопоставленияПлатежей.Очистить();
    ТекНастройки = Новый ЧтениеТекста;    
    // ОШИБКА ЗДЕСЬ: Попытка открыть локальный файл клиента на сервере
    ТекНастройки.Открыть(Объект.ФайлНастроек);                  
    СтрокаНастроек = ТекНастройки.ПрочитатьСтроку();
    // ... дальнейший парсинг ...
КонецПроцедуры

Выясним причину такого поведения. В файловой базе клиент и сервер физически выполняются в одном процессе на одной машине, поэтому серверный контекст имеет доступ к локальному диску `C:\` пользователя. Однако в полноценной клиент-серверной архитектуре сервер 1С — это отдельный компьютер. Когда код, выполняющийся под директивой &НаСервере, пытается обратиться по пути локального файла пользователя (например, C:\Users\User\Desktop\settings.txt), он ищет этот файл на жестком диске самого сервера 1С. Разумеется, файла там нет, и система выдает ошибку.

Решение 1: Правильная передача файла через Временное хранилище

Чтобы код работал корректно, нам нужно передать содержимое файла с клиента на сервер. В платформе 1С для этого используется механизм временного хранилища. Разберем по шагам правильный алгоритм действий:

  1. Выбор файла пользователем с помощью диалога выбора &НаКлиенте.
  2. Помещение выбранного файла во временное хранилище на клиенте. Платформа создает специальный адрес (строку), по которому данные доступны.
  3. Передача этого адреса-ссылки в процедуру &НаСервере.
  4. Получение данных из временного хранилища на сервере и их дальнейшая обработка.

В современных релизах платформы (начиная с 8.3.18) рекомендуется использовать асинхронные методы работы с файлами. Посмотрим на пример правильной загрузки файла:


&НаКлиенте
Асинх Процедура ЗагрузитьНастройки(Команда)
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Текстовые файлы (*.txt)|*.txt";
    
    // Ожидаем выбора файла пользователем
    РезультатВыбора = Ждать Диалог.ВыбратьАсинх();
    Если РезультатВыбора = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Помещаем файл во временное хранилище
    ПараметрыПомещения = Новый ПараметрыПомещенияФайловНаСервер;
    РезультатПомещения = Ждать ПоместитьФайлНаСерверАсинх(РезультатВыбора[0], УникальныйИдентификатор, ПараметрыПомещения);
    
    // Передаем адрес хранилища на сервер
    ПрочитатьНастройкиНаСервере(РезультатПомещения.Адрес);
КонецПроцедуры

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

Решение 2: Использование встроенных хранилищ настроек 1С

Если нет строгой необходимости передавать настройки именно в виде текстового файла между разными базами, лучше вообще отказаться от работы с файловой системой. В платформу встроены мощные механизмы: ХранилищеОбщихНастроек и ХранилищеСистемныхНастроек.

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


&НаСервере
Процедура СохранитьНастройкиВБазу()
    КлючОбъекта = "МояОбработка_СопоставлениеПлатежей";
    КлючНастроек = "ОсновныеНастройки";
    
    // Выгружаем данные табличной части в Таблицу Значений
    ТаблицаНастроек = Объект.СопоставленияПлатежей.Выгрузить();
    
    // Сохраняем в системное хранилище
    ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, КлючНастроек, ТаблицаНастроек);
КонецПроцедуры

&НаСервере
Процедура ЗагрузитьНастройкиИзБазы()
    КлючОбъекта = "МояОбработка_СопоставлениеПлатежей";
    КлючНастроек = "ОсновныеНастройки";
    
    ТаблицаНастроек = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта, КлючНастроек);
    
    Если ТаблицаНастроек <> Неопределено Тогда
        Объект.СопоставленияПлатежей.Загрузить(ТаблицаНастроек);
    КонецЕсли;
КонецПроцедуры

Этот метод полностью снимает все вопросы с передачей файлов между клиентом и сервером и работает молниеносно.

Ошибки парсинга: почему не стоит использовать кастомные разделители?

В исходном коде автора используется формирование строки через кастомный разделитель & с последующим разбиением через функцию СтрРазделить. Проанализируем, почему этот подход является хрупким.

Если в наименовании контрагента или договора встретится символ амперсанда (например, "Рога & Копыта"), массив сместится. Индексы элементов перестанут соответствовать ожидаемым колонкам, и код завершится с ошибкой или запишет некорректные данные.

Вместо ручного разбора строк в современной разработке на 1С принято использовать JSON или XML сериализацию. Платформа 1С умеет автоматически конвертировать большинство структур данных в стандартные форматы, заботясь об экранировании всех спецсимволов. Рассмотрим пример преобразования массива структур в JSON:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
// Предположим, ДанныеНастроек - это массив или структура
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ДанныеНастроек);
СтрокаJSON = ЗаписьJSON.Закрыть();

Риски использования метода НайтиПоНаименованию

И наконец, разберем еще одну критическую ошибку в логике восстановления данных. В процедуре загрузки настроек мы видим следующий код:


СтрСопоставленияПлатежей.Контрагент = Справочники.Контрагенты.НайтиПоНаименованию(МассивСтроки[1]);

Искать ссылки по текстовому наименованию — это серьезный антипаттерн в 1С. Наименования справочников часто меняются пользователями (исправление опечаток, смена формы собственности ООО/ЗАО, добавление пробелов). Кроме того, в базе могут быть дубли наименований. При следующей загрузке файла система либо найдет не того контрагента, либо вернет пустую ссылку.

Как делать правильно? Если настройки выгружаются во внешний файл, сохранять и читать нужно не строковые имена, а Уникальный Идентификатор (GUID) ссылочного объекта. При записи в файл мы сохраняем результат функции Строка(Контрагент.УникальныйИдентификатор()). А при чтении восстанавливаем ссылку надежным методом:


// Восстановление ссылки по GUID из строки файла
ГУИД_Контрагента = Новый УникальныйИдентификатор(СтрокаИзФайла);
СтрСопоставленияПлатежей.Контрагент = Справочники.Контрагенты.ПолучитьСсылку(ГУИД_Контрагента);

Использование GUID гарантирует 100% точное сопоставление данных вне зависимости от переименований элементов в базе данных.

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

← На главную