В разработке на платформе «1С:Предприятие 8.3» одним из фундаментальных правил является четкое разделение контекста исполнения кода на клиентский и серверный. Клиент отвечает за взаимодействие с пользователем и отображение интерфейса, в то время как сервер выполняет тяжелые вычисления, работу с базой данных и бизнес-логику. Рано или поздно перед каждым разработчиком встает задача: как передать данные, доступные на клиенте, в серверную процедуру?
Особую сложность этот вопрос вызывает тогда, когда речь заходит о файлах и путях к ним. В этой статье мы подробно разберем, как правильно передавать простые значения, почему прямая передача пути к файлу является ошибкой, и как организовать корректный перенос файлов с клиентского компьютера на сервер с использованием современных механизмов платформы.
Прежде чем перейти к написанию кода, давайте проанализируем, почему нельзя просто так взять и использовать клиентские данные на сервере. Клиентское приложение (тонкий клиент, веб-клиент) и сервер приложений 1С — это физически разные процессы, которые могут выполняться на абсолютно разных компьютерах, находящихся в разных точках мира.
Для обмена данными между ними платформа выполняет операцию сериализации — перевода объектов 1С в поток байтов (обычно XML или JSON) для передачи по сети, и последующей десериализации на принимающей стороне. Из этого вытекает первое золотое правило разработки:
Между клиентом и сервером можно передавать только те типы данных, которые поддерживают сериализацию.
К таким типам относятся:
Число, Строка, Булево, Дата, Неопределено.Массив, Структура, Соответствие, а также ТаблицаЗначений (последняя — с ограничениями: ее колонки должны содержать только сериализуемые типы).Такие объекты, как ДиалогВыбораФайла, COM-объекты, драйверы оборудования или открытые сессии внешних соединений, существуют исключительно в памяти клиента и не могут быть переданы на сервер.
Рассмотрим простейшую ситуацию: на клиенте у нас есть текстовая строка (например, артикул товара или поисковый запрос), и нам нужно обработать ее на сервере. Самый очевидный и правильный способ — передать это значение в качестве параметра при вызове серверного метода.
Давайте посмотрим на практический пример:
&НаКлиенте
Процедура ВыполнитьПоискНаКлиенте()
СтрокаПоиска = "Шоколад Аленка"; // Значение получено на клиенте
// Передаем значение в качестве параметра серверной функции
НайденныеТовары = НайтиТоварыНаСервере(СтрокаПоиска);
// Обрабатываем результат на клиенте
Если НайденныеТовары.Количество() > 0 Тогда
ПоказатьПредупреждение(, "Товары успешно найдены!");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция НайтиТоварыНаСервере(Знач ПоисковыйЗапрос)
// Серверный контекст. Здесь доступна база данных.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Наименование ПОДОБНО &Наименование";
Запрос.УстановитьПараметр("Наименование", "%" + ПоисковыйЗапрос + "%");
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецФункции
В данном примере мы использовали директиву компиляции &НаСервереБезКонтекста. Это наиболее эффективный метод вызова сервера, так как при этом на сервер не передаются данные всей формы (ее реквизиты), что существенно экономит сетевой трафик и ускоряет работу системы.
Очень часто начинающие разработчики совершают классическую ошибку. Получив на клиенте путь к файлу (например, "C:\Users\User\Documents\Report.xlsx"), они передают эту строку на сервер в надежде, что серверный код сможет открыть и прочитать этот файл. Давайте выясним, почему эта схема обречена на провал в реальной эксплуатации.
Если база данных работает в файловом режиме на одном и том же компьютере разработчика, этот код сработает. Но как только конфигурация будет развернута в полноценном клиент-серверном варианте, произойдет следующее:
usr1cv8)."C:\Users\User\Documents\Report.xlsx", он попытается найти этот файл на своем собственном локальном диске "C:". Разумеется, такого файла там нет, и система вернет ошибку доступа или сообщение о том, что файл не найден.Исключение из правила: Передача строкового пути имеет смысл только тогда, когда файл лежит в общей сетевой папке (имеет UNC-путь вида \\ServerName\ShareFolder\file.xlsx) и служба сервера 1С имеет полные права операционной системы на чтение и запись в эту сетевую директорию. Во всех остальных случаях необходимо передавать на сервер сам файл, а не путь к нему.
Единственный надежный способ обработать клиентский файл на сервере — это переслать его содержимое в виде двоичных данных. Для этого в платформе 1С предусмотрен специальный механизм — Временное хранилище.
Временное хранилище представляет собой выделенную область памяти на сервере приложений 1С, куда клиент может временно поместить данные и получить уникальный строковый адрес вида e1cib/tempstorage/.... Этот адрес легко передается между клиентом и сервером как обычная строка.
Давайте разберем по шагам классический программный алгоритм передачи файла, когда путь к файлу на клиенте нам уже известен:
&НаКлиенте
Процедура ПередатьФайлНаСервер()
ПутьКФайлуНаКлиенте = "C:\MyFiles\Data.txt"; // Путь на клиентском ПК
// Шаг 1. Читаем файл в объект ДвоичныеДанные на клиенте
Попытка
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлуНаКлиенте);
Исключение
Сообщить("Не удалось прочитать файл на клиенте: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Шаг 2. Помещаем двоичные данные во временное хранилище.
// Привязываем адрес к УникальномуИдентификатору формы.
// Это гарантирует, что платформа автоматически очистит память при закрытии формы.
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, ЭтаФорма.УникальныйИдентификатор);
// Шаг 3. Передаем адрес на сервер для обработки
ОбработатьФайлНаСервере(АдресВременногоХранилища);
КонецПроцедуры
&НаСервере
Процедура ОбработатьФайлНаСервере(Знач АдресХранилища)
// Шаг 4. На сервере получаем двоичные данные по адресу
ДвоичныеДанныеНаСервере = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ДвоичныеДанныеНаСервере = Неопределено Тогда
ВызватьИсключение "Ошибка получения данных из временного хранилища!";
КонецЕсли;
// Шаг 5. Создаем временный файл на сервере для последующего анализа
ИмяВременногоФайлаНаСервере = ПолучитьИмяВременногоФайла("txt");
ДвоичныеДанныеНаСервере.Записать(ИмяВременногоФайлаНаСервере);
// Шаг 6. Здесь выполняется непосредственное чтение и обработка файла.
// Например, чтение текстового файла:
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ИмяВременногоФайлаНаСервере);
Для НомерСтроки = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл
СтрокаТекста = ТекстовыйДокумент.ПолучитьСтроку(НомерСтроки);
// Выполняем бизнес-логику...
КонецЦикла;
// Шаг 7. Обязательно удаляем временный файл на сервере, чтобы не переполнять диск!
Попытка
УдалитьФайлы(ИмяВременногоФайлаНаСервере);
Исключение
ЗаписьЖурналаРегистрации("ОчисткаВременныхФайлов", УровеньЖурналаРегистрации.Предупреждение,,,
"Не удалось удалить временный файл: " + ИмяВременногоФайлаНаСервере);
КонецПопытки;
КонецПроцедуры
В современных конфигурациях 1С, работающих в управляемом режиме (особенно в веб-клиенте), синхронные методы работы с файлами считаются устаревшими и могут вызывать блокировку интерфейса. Платформа предоставляет мощный асинхронный инструмент: метод НачатьПомещениеФайлаНаСервер().
Этот метод работает асинхронно, открывает стандартное окно выбора файлов для пользователя и автоматически отправляет выбранный файл во временное хранилище, возвращая управление в специальную процедуру-оповещение. Давайте разберем этот продвинутый паттерн программирования:
&НаКлиенте
Процедура НачатьЗагрузкуФайла(Команда)
// Описываем, какую процедуру вызвать после того, как файл будет загружен в облако/сервер
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗагрузкиФайлаНаСервер", ЭтотОбъект);
ПараметрыЗагрузки = Новый ПараметрыПомещенияФайлаНаСервер;
ПараметрыЗагрузки.Интерактивно = Истина; // Откроет диалог выбора файла
ПараметрыЗагрузки.Заголовок = "Выберите файл для обработки на сервере";
// Запускаем асинхронный процесс
НачатьПомещениеФайлаНаСервер(ОписаниеОповещения,,,, ПараметрыЗагрузки, ЭтаФорма.УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗагрузкиФайлаНаСервер(РезультатПомещения, ДополнительныеПараметры) Экспорт
// Проверяем, успешно ли завершился процесс
Если РезультатПомещения <> Неопределено И РезультатПомещения.ИмяФайлаПомещено Тогда
// Адрес временного хранилища находится в свойстве "Адрес"
АдресХранилища = РезультатПомещения.Адрес;
ИмяФайла = РезультатПомещения.СсылкаНаФайл.Имя;
Сообщить(СтрШаблон("Файл %1 успешно загружен. Отправляем на сервер...", ИмяФайла));
// Передаем адрес во временном хранилище на сервер для разбора
РазобратьДанныеНаСервере(АдресХранилища);
Иначе
ПоказатьПредупреждение(, "Загрузка файла была отменена пользователем.");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура РазобратьДанныеНаСервере(Знач АдресХранилища)
// Извлекаем двоичные данные на сервере без контекста формы
ДанныеФайла = ПолучитьИзВременногоХранилища(АдресХранилища);
// Выполняем обработку...
// (например, парсинг Excel, чтение XML-данных или загрузка картинок)
КонецПроцедуры
Работа с временным хранилищем требует аккуратности, особенно в высоконагруженных системах с сотнями одновременно работающих пользователей. Проанализируем ключевые рекомендации по обеспечению стабильности и производительности:
ПоместитьВоВременноеХранилище() всегда передавайте вторым параметром ЭтаФорма.УникальныйИдентификатор. Если этого не сделать, данные будут жить в памяти сервера до окончания сеанса пользователя. Если пользователь загрузит десяток тяжелых файлов по 100 МБ, сервер быстро исчерпает доступную оперативную память. Привязка к форме уничтожит эти данные сразу после закрытия окна формы.ПолучитьИмяВременногоФайла(), всегда помещайте блок удаления файла в конструкцию Попытка...Исключение. Не удаленные временные файлы операционной системы способны за несколько недель полностью забить дисковое пространство сервера приложений 1С.&НаСервереБезКонтекста. Платформа сама оптимизирует процесс ее сериализации.Подводя итог, можно сказать, что передача клиентских значений на сервер — стандартная и ежедневная задача разработчика 1С. Понимание принципов сериализации данных и механизмов работы с временным хранилищем позволит вам писать надежный, быстрый и отказоустойчивый код, который будет корректно работать в любых архитектурных условиях.