При разработке интеграций и механизмов загрузки данных часто возникает задача: пользователь выбирает несколько файлов на своем локальном компьютере (например, выгрузки в формате CSV), а сервер должен прочитать их содержимое и сформировать таблицу значений или записать данные в информационную базу. Однако начинающие разработчики нередко сталкиваются с тем, что простая передача массива путей к файлам на сторону сервера не работает. Разберем детально, почему так происходит и как правильно организовать передачу и обработку файлов в клиент-серверной архитектуре 1С.
Проанализируем ключевую причину проблемы. В управляемом приложении клиентская часть и серверная часть физически разделены. Локальные пути к файлам вида C:\Documents\data.csv существуют только в файловой системе рабочего компьютера пользователя. Сервер 1С (процесс rphost), работая на отдельном сервере, ничего не знает об этих путях и не имеет к ним доступа. Чтобы сервер смог обработать данные, сами файлы необходимо предварительно передать через сеть.
Рассмотрим основной штатный механизм платформы «1С:Предприятие 8.3». Он заключается в интерактивном или программном помещении файлов во временное хранилище на клиенте с последующей передачей полученных уникальных адресов на сервер.
Посмотрим на пример загрузки одиночного файла через асинхронные оповещения, рассмотренный участниками обсуждения:
&НаКлиенте
Процедура ЗагрузитьДанныеИзВнешнегоФайла(Команда)
ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьВыборВнешнегоФайла", ЭтаФорма);
ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытияФайла.Фильтр = "Файлы CSV (*.csv)|*.csv";
НачатьПомещениеФайла(ОписаниеОповещения, , ДиалогОткрытияФайла, Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьВыборВнешнегоФайла(ФайлВыбран, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если НЕ ФайлВыбран Тогда
Возврат;
КонецЕсли;
ЗагрузитьДанныеИзФайлаНаСервере(Адрес);
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьДанныеИзФайлаНаСервере(АдресФайла)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресФайла);
// Обработка двоичных данных на сервере
КонецПроцедуры
Когда требуется выбрать и передать сразу массив файлов, разберем по шагам модернизацию этого механизма:
МножественныйВыбор = Истина у объекта ДиалогВыбораФайла. Это критично, особенно для веб-клиента, где браузерная безопасность запрещает прямое сканирование локальных дисков без интерактивного выбора пользователя.ПоместитьФайлыНаСерверАсинх (или НачатьПомещениеФайловНаСервер). Сформируем массив объектов ОписаниеПередаваемогоФайла и отправим их во временное хранилище.ПолучитьИзВременногоХранилища.Посмотрим на пример работы с группой файлов:
&НаКлиенте
Асинх Процедура ВыбратьИЗагрузитьМассивФайлов(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.МножественныйВыбор = Истина;
Диалог.Фильтр = "Файлы CSV (*.csv)|*.csv";
Если Не Ждать Диалог.ВыбратьАсинх() Тогда
Возврат;
КонецЕсли;
МассивФайловДляПомещения = Новый Массив;
Для Каждого ИмяФайла Из Диалог.ВыбранныеФайлы Цикл
МассивФайловДляПомещения.Добавить(Новый ОписаниеПередаваемогоФайла(ИмяФайла));
КонецЦикла;
МассивРезультатов = Ждать ПоместитьФайлыНаСерверАсинх(МассивФайловДляПомещения, , , УникальныйИдентификатор);
Если МассивРезультатов = Неопределено Или МассивРезультатов.Количество() = 0 Тогда
Возврат;
КонецЕсли;
МассивАдресов = Новый Массив;
Для Каждого Описание Из МассивРезультатов Цикл
МассивАдресов.Добавить(Описание.Адрес);
КонецЦикла;
ОбработатьФайлыНаСервере(МассивАдресов);
КонецПроцедуры
Выясним, как сертифицированно и производительно разобрать полученные двоичные данные на сервере. Частая ошибка разработчиков — сохранять ДвоичныеДанные обратно во временный файл на жесткий диск сервера через ПолучитьИмяВременногоФайла(). Это создает лишние операции ввода-вывода (I/O) и замедляет работу.
Платформа 1С позволяет открыть поток для чтения напрямую из памяти. Для работы со структурированными файлами CSV предназначен объект ЧтениеCSV, который корректно обрабатывает кавычки, разделители и переносы строк внутри колонок, исключая ошибки самописного разбора через метод СтрРазделить.
&НаСервере
Процедура ОбработатьФайлыНаСервере(МассивАдресов)
ТаблицаРезультат = Новый ТаблицаЗначений;
// Определение колонок таблицы
ТаблицаРезультат.Колонки.Добавить("Артикул", Новый ОписаниеТипов("Строка"));
ТаблицаРезультат.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Для Каждого Адрес Из МассивАдресов Цикл
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
ЧтениеCSV = Новый ЧтениеCSV;
ЧтениеCSV.ОткрытьПоток(Поток);
Пока Истина Цикл
МассивДанныхСтроки = ЧтениеCSV.ПрочитатьСтроку();
Если МассивДанныхСтроки = Неопределено Тогда
Прервать;
КонецЕсли;
НоваяСтрока = ТаблицаРезультат.Добавить();
НоваяСтрока.Артикул = МассивДанныхСтроки[0];
НоваяСтрока.Количество = Число(МассивДанныхСтроки[1]);
КонецЦикла;
ЧтениеCSV.Закрыть();
Поток.Закрыть();
// Очищаем память временного хранилища после обработки файла
УдалитьИзВременногоХранилища(Адрес);
КонецЦикла;
// Дальнейшая работа со сформированной ТаблицейРезультат
КонецПроцедуры
Проанализируем важный нюанс: если файлов десятки или сотни, единовременное помещение всех файлов во временное хранилище создает резкую нагрузку на оперативную память рабочих процессов rphost. При исчерпании лимитов памяти сеанс пользователя может аварийно завершиться.
Для предотвращения подобных сбоев применим пакетную обработку: организуем цикл на клиенте, в котором каждый файл поочередно помещается во временное хранилище, передается на сервер, обрабатывается там, а адрес немедленно очищается вызовом метода УдалитьИзВременногоХранилища перед переходом к следующей итерации.
Если файлов очень много, сетевые накладные расходы на вызов передачи каждого файла могут затянуть процесс. В таких ситуациях эффективно сжать их на стороне клиента:
ЗаписьZipФайла и добавляем в него найденные CSV-файлы.ЧтениеZipФайла, распаковываем файлы в КаталогВременныхФайлов() сервера или читаем их потоками, после чего парсим данные в таблицу значений.Если клиент и сервер находятся в единой локальной сети, можно скопировать файлы в общую сетевую папку (UNC-путь, например: \\server-share\upload\) и передать на сервер массив сетевых путей.
Важное ограничение: служба сервера 1С по умолчанию запускается от имени локальной системной учетной записи usr1cv8. Данный пользователь не имеет прав доступа к сетевым ресурсам за пределами своего сервера. Чтобы этот способ работал, системный администратор должен запускать службу 1С под доменной учетной записью с явными правами на чтение и запись в целевую сетевую папку.