При разработке в клиент-серверной архитектуре 1С:Предприятия разработчики нередко сталкиваются с ситуацией, когда файл находится на компьютере пользователя (клиенте), а логику разбора данных и записи в базу необходимо выполнить на сервере. Попытка передать путь к файлу или напрямую объект ЧтениеXML на сервер приводит к ошибкам «Файл не найден» или «Ошибка передачи данных между клиентом и сервером».
Разберем детально, почему возникают эти проблемы, и рассмотрим проверенные способы корректного чтения и обработки XML-файлов.
Выясним причину типичных ошибок, с которыми сталкиваются при реализации загрузки данных:
C:\Data\file.xml, переданный в серверную процедуру, будет искаться сервером на его собственном диске.ЧтениеXML: Этот объект предназначен для последовательного чтения потока XML и не может быть передан через границу клиент-серверного вызова.ЧтениеXML.Прочитать() не принимает путь к файлу в качестве параметра, а лишь считывает следующий узел уже открытого потока.Рассмотрим основной и наиболее универсальный метод передачи файлов в управляемом приложении. Файл отправляется во временное хранилище на клиенте, после чего сервер считывает его двоичные данные без сохранения на постоянный диск.
Посмотрим на реализацию выбора и передачи файла:
&НаКлиенте
Процедура ВыбратьИЗагрузитьФайл(Команда)
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Фильтр = "Файлы XML (*.xml)|*.xml";
ПараметрыДиалога.Заголовок = "Выберите файл для загрузки";
Оповещение = Новый ОписаниеОповещения("ВыбратьИЗагрузитьФайлЗавершение", ЭтотОбъект);
НачатьПомещениеФайлаНаСервер(Оповещение, , , ПараметрыДиалога, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ВыбратьИЗагрузитьФайлЗавершение(ОписаниеФайла, ДополнительныеПараметры) Экспорт
Если ОписаниеФайла = Неопределено Тогда
Возврат;
КонецЕсли;
// Передаем адрес временного хранилища на сервер
ПрочитатьXMLНаСервере(ОписаниеФайла.Адрес);
КонецПроцедуры
Теперь разберем обработку полученных данных на сервере. В современных версиях платформы чтение можно выполнить напрямую из потока памяти, не создавая временных файлов на диске сервера:
&НаСервере
Процедура ПрочитатьXMLНаСервере(АдресВременногоХранилища)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
// Открываем поток для чтения данных из памяти
Поток = ДвоичныеДанные.ОткрытьПотокДляЧтения();
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьПоток(Поток);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяЭлемента = ЧтениеXML.Имя;
// Обработка данных узлов XML
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
// Очищаем временное хранилище после завершения обработки
УдалитьИзВременногоХранилища(АдресВременногоХранилища);
КонецПроцедуры
Проанализируем вариант для работы с небольшими XML-документами (размером в несколько мегабайт). Файл считывается в строковую переменную на стороне клиента, после чего строка передается параметром в серверную процедуру.
Посмотрим на пример клиентского кода с использованием объекта ЧтениеТекста:
&НаКлиенте
Процедура ПрочитатьЧерезСтроку(ПутьКФайлу)
ЧтениеТекста = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8);
СтрокаXML = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
Если Не ПустаяСтрока(СтрокаXML) Тогда
РазобратьСтрокуXMLНаСервере(СтрокаXML);
КонецЕсли;
КонецПроцедуры
На сервере инициализируем парсер с помощью метода УстановитьСтроку:
&НаСервере
Процедура РазобратьСтрокуXMLНаСервере(СтрокаXML)
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаXML);
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
// Чтение структуры документа
КонецЕсли;
КонецЦикла;
ЧтениеXML.Закрыть();
КонецПроцедуры
Важно: Не используйте передачу через строку для больших файлов (десятки и сотни мегабайт), так как это вызовет повышенное потребление оперативной памяти и задержки при сериализации сетевого вызова.
Разберем еще один подход, который позволяет снять нагрузку с сервера при разборе тяжелых XML-структур в тонком или толстом клиенте:
ЧтениеXML.ОткрытьФайл(ПутьКФайлу).Массив структур или соответствий).Такой подход минимизирует объем данных, пересылаемых по сети, и позволяет серверу сосредоточиться исключительно на транзакционной записи в базу данных.