1с прочитать xml из хранилища
Данная публикация не претендует на использование в продакшене, но когда "Нельзя, но очень хочется" в отношении получения ооочень больших данных из ХранилищаЗначения и когда сама платформа не может получить значение и падает, при этом, перед падением съедает почти всю память. Это своего рода костыль, в безвыходной ситуации. Речь пойдет про получение больших данных из хранилища значения в файловых базах на 32-х битной платформе. Данное не касается 64-х битных клиентов/серверов где нет ограничения на размер потребляемой памяти (верней есть, но доступно памяти гораздо больше, чем 32-х битному приложению без PAE).
А вы знали? 1С любит держать данные помещенные в ХранилищеЗначения в временном файле на диске? Разумеется имеется ввиду те данные, то лежат в памяти. Возможно, она так любит избавляться только от больших данных, но это уже совсем другая история.
Суть решения "проста", запакованное хранилище значения из себя представляет данные, запакованные алгоритмом Deflate (которая сама 1С использует везде, а доступа к методам дать не могут) и некоторое служебные данные. Этим же методом Deflate, упаковываются ZIP архивы. Итого весь процесс проводится к следующему:
1) Получение из хранилища значений двоичных данных (да-да, 1С не добавила возможности прямого получения):
2) Получаем буфер двоичных за вычетом префикса хранилища значения
3) Формируем структуру ZIP архива и добавляем к нему данные из буфера двоичных данных
4) Распаковать ZIP архив, игнорируя ошибки распаковки (так как у нас нет данных о CRC сумме НЕ запакованных данных, а так же об их размере)
5) На выходе, мы уже получаем распакованные данные, которые были помещены в хранилище значения, НО, они окружены структурой, похожей на JSON которая всюду используется в 1С как минимум с 1С 7.7 (или даже раньше), для того чтобы от неё избавится, надо в начале файла отрезать чуток и в конце, а так-же убрать экранирование кавычек. Тут я пробовал разные варианты (кроме считывания всего текста и СтрЗаменить, ибо память не безлимитная, но и такой способ работает и 1С не падает), но самым оптимальным как по скорости, так и по потреблению памяти, оказалось порционное чтение из файла, замена двойных кавычек на одинарные и запись в результирующий файл (выполняется мгновенно, пруфов нет)
7) Так же не забывайте убирать за собой, помогите сборщику мусора 1С, донесите свой мусор хотя бы до помойки:
Как и писалось в анонсе, данный способ не претендует на использование в продакшене (хотя мы у себя впилили, вместо ХранилищеЗначение.Получить() на проде), но надеюсь, данная публикация вам поможет, когда нужно через хранилище значения, передать много данных, а штатный механизм прожорлив или вообще падает (как в моём случае). Разумеется, вы бы сделали лучше чем я и код фактически один большой костыль.
Тем же, кто думает о своей реализации обмена данными через веб-сервис, я бы пожалуй посоветовал паковку в ZIP архив на сервере (можно даже в памяти это сделать, без записи на диск) и передавать двоичные данные, а на клиенте уже сохранить полученные двоичные данные на диск, а дальше можно использовать типовой механизм.
Выражаю благодарность автору обработки, которая сделала сказку - былью!
Если у вас есть лишние помидоры и яйца, то вспомните о голодающих ;)
PS: Прошу обратить внимание на то, что данная публикация, получает строку, помещенную в хранилище значение, если вы хотите таким образов получать другие типы данных помещенные в хранилище значение, вам явно придется вооружится напильником, но нет ничего не возможного!
PS: Так же надо учитывать, что данный способ медленней чем штатный способ получения значения! Обратите так же внимание, тестировать обработку лучше в файловой базе или хотя бы на 32-х битном сервере 1С, где есть техническое ограничение на потребляемую память. На 64-х битном сервере 1С, даже очень большие данные сможет получить. Да, обработка не демонстрирует проблему, а демонстрирует решение.
Здравствуйте. На Клиенте с помощью предназначенного для этого метода происходит интерактивный выбор файла XML пользователем (по сути это текстовый файл), файл записывается во временное хранилище.
Затем на сервере значение из временного хранилища необходимо получить в виде строки-содержимого.
В данный момент использую следующий код:
1) Является ли этот код оптимальным и правильным для поставленной задачи на современных платформах?
2) Есть ли способ решить подобную задачу на платформах до 8.3.9, в которых объект ЧтениеДанных отсутствовал?
(1)
1. Правильным - да, оптимальным - нет, т.к. происходит чтение всего файла XML в ОЗУ.
2. Как-то так:
Но да, на веб клиенте не доступно, но и в (1) про него не упоминалось.
Тогда для веб клиента можно на сервере читать через ЧтениеТекста вместо ЧтениеДанных.
(1)
1. Правильным - да, оптимальным - нет, т.к. происходит чтение всего файла XML в ОЗУ.
2. Как-то так:
(2) Этот вариант тоже читает файл в память - метод получения двочиных данных.
Вообще, если делать быстро, то надо вообще вот так делать (при файлах не очень большого размера):
Код |
---|
Показать полностью |
Ну так можно просто сохранить, потом ДД = ""; - все, память очистили. Потом прочитать из файла уже по старорежжимному.
(3) в первом случае файл целиком читается в ОЗУ, а в случае, что описал я - нет, в этом принципиальное отличие подходов.
Если чтение в виде двоичных данных можно делать как-то частями и при этом прочитанную часть можно обработать, то делать нужно именно так.
Это не чтение файла целиком в ОЗУ? Двоичные данные контейнера что содержат?
При получении на сервере значения из временного хранилища следует учитывать то, что оно получается по ссылке. В действительности, ссылка эта указывает на значение, которое хранится в кеше . В течение 20 минут, с момента помещения в хранилище или же с момента последнего обращения, значение сохранится в кеше, а затем записывается на диск и из кеша удаляется. При следующем обращении значение загружается с диска и снова помещается в кеш.
Фактически, кеш - это память, которая через 20 минут выгрузится на диск. При варианте с двоичными данными, передаваемыми на сервер, память экономится только на клиенте.
(7)хорошо. Убираем помещение ДД во ВрХр и получение из него - читаем XML и формируем ОбъектXDTO прямо на клиенте.
В принципе даже работает, но не все. Объект XDTO - это тоже все в памяти, поэтому лучше последовательно читать, особенно если файл большой. По крайней мере результат вебсервиса - объект тот самый - не ездит между сервером и клиентом, ну и веб-сервисы на клиенте не работают.
Если файло большое, то совсем правильно читать его и скармливать фоновым заданиям прочитанное (по сотне единиц, например).
(11)Я ж привел пример чтения по одному ОбъектXDTO - он занимает минимально возможное для своего существования место в ОЗУ.
А вот х.з., можно будет ОбъектXDTO, сформированный на клиенте передать на сервер или нет :)
(12) впринципе, для объекта XDTO у 1С есть своя модель данных в базовых пакетах, т.е. он вроде как сериялизуется, а все, что сериализуется, может ездить туды-сюды, если там и сям доступно.
На Клиенте с помощью предназначенного для этого метода происходит интерактивный выбор файла XML пользователем (по сути это текстовый файл), файл записывается во временное хранилище.
Есть ли способ решить подобную задачу на платформах до 8.3.9, в которых объект ЧтениеДанных отсутствовал?
(6) Я понял идею, но не понял реализацию, уточните пожалуйста. ЧтениеТекста получает файл по пути в системе, а не выбирает его интерактивно, кроме того, оно недоступно на веб-клиенте. Методы для работы с файловой системой (такие как НачатьПомещениеФайлаНаСервер) все и во всех платформах помещают файл в виде двоичных данных во временное хранилище.
Но да, на веб клиенте не доступно, но и в (1) про него не упоминалось.
Тогда для веб клиента можно на сервере читать через ЧтениеТекста вместо ЧтениеДанных.
Действительно, если вся задача – это получить СтрокаXML на сервере, то достаточно передать строку в параметрах серверной процедуры, минуя и временное хранилище и объекты работы с данными.
(8) Это было бы прекрасно, только расскажите мне как интерактивно выбрать файл на клиенте и получить из него строку-содержимое тоже на клиенте, с учетом поддержки всех видов клиента (см. ответ (14)).
Данная публикация не претендует на использование в продакшене, но когда "Нельзя, но очень хочется" в отношении получения ооочень больших данных из ХранилищаЗначения и когда сама платформа не может получить значение и падает, при этом, перед падением съедает почти всю память. Это своего рода костыль, в безвыходной ситуации. Речь пойдет про получение больших данных из хранилища значения в файловых базах на 32-х битной платформе. Данное не касается 64-х битных клиентов/серверов где нет ограничения на размер потребляемой памяти (верней есть, но доступно памяти гораздо больше, чем 32-х битному приложению без PAE).
А вы знали? 1С любит держать данные помещенные в ХранилищеЗначения в временном файле на диске? Разумеется имеется ввиду те данные, то лежат в памяти. Возможно, она так любит избавляться только от больших данных, но это уже совсем другая история.
Суть решения "проста", запакованное хранилище значения из себя представляет данные, запакованные алгоритмом Deflate (которая сама 1С использует везде, а доступа к методам дать не могут) и некоторое служебные данные. Этим же методом Deflate, упаковываются ZIP архивы. Итого весь процесс проводится к следующему:
1) Получение из хранилища значений двоичных данных (да-да, 1С не добавила возможности прямого получения):
2) Получаем буфер двоичных за вычетом префикса хранилища значения
3) Формируем структуру ZIP архива и добавляем к нему данные из буфера двоичных данных
4) Распаковать ZIP архив, игнорируя ошибки распаковки (так как у нас нет данных о CRC сумме НЕ запакованных данных, а так же об их размере)
5) На выходе, мы уже получаем распакованные данные, которые были помещены в хранилище значения, НО, они окружены структурой, похожей на JSON которая всюду используется в 1С как минимум с 1С 7.7 (или даже раньше), для того чтобы от неё избавится, надо в начале файла отрезать чуток и в конце, а так-же убрать экранирование кавычек. Тут я пробовал разные варианты (кроме считывания всего текста и СтрЗаменить, ибо память не безлимитная, но и такой способ работает и 1С не падает), но самым оптимальным как по скорости, так и по потреблению памяти, оказалось порционное чтение из файла, замена двойных кавычек на одинарные и запись в результирующий файл (выполняется мгновенно, пруфов нет)
7) Так же не забывайте убирать за собой, помогите сборщику мусора 1С, донесите свой мусор хотя бы до помойки:
Как и писалось в анонсе, данный способ не претендует на использование в продакшене (хотя мы у себя впилили, вместо ХранилищеЗначение.Получить() на проде), но надеюсь, данная публикация вам поможет, когда нужно через хранилище значения, передать много данных, а штатный механизм прожорлив или вообще падает (как в моём случае). Разумеется, вы бы сделали лучше чем я и код фактически один большой костыль.
Тем же, кто думает о своей реализации обмена данными через веб-сервис, я бы пожалуй посоветовал паковку в ZIP архив на сервере (можно даже в памяти это сделать, без записи на диск) и передавать двоичные данные, а на клиенте уже сохранить полученные двоичные данные на диск, а дальше можно использовать типовой механизм.
Выражаю благодарность автору обработки, которая сделала сказку - былью!
Если у вас есть лишние помидоры и яйца, то вспомните о голодающих ;)
PS: Прошу обратить внимание на то, что данная публикация, получает строку, помещенную в хранилище значение, если вы хотите таким образов получать другие типы данных помещенные в хранилище значение, вам явно придется вооружится напильником, но нет ничего не возможного!
PS: Так же надо учитывать, что данный способ медленней чем штатный способ получения значения! Обратите так же внимание, тестировать обработку лучше в файловой базе или хотя бы на 32-х битном сервере 1С, где есть техническое ограничение на потребляемую память. На 64-х битном сервере 1С, даже очень большие данные сможет получить. Да, обработка не демонстрирует проблему, а демонстрирует решение.
Всем привет. Подскажите, пожалуйста, как перенести из одной базы в другую данные типа "ХранилищеЗначений". Пробую через xml. Сначала записываю:
ЗаписьХМЛ = Новый ЗаписьXML;
ЗаписьХМЛ.ОткрытьФайл("D:\doc.xml");
ЗаписьХМЛ.ЗаписатьОбъявлениеXML();
Для Каждого Строка Из Выгрузка Цикл
ЗаписьХМЛ.ЗаписатьНачалоЭлемента("Пользователь");
ЗаписьХМЛ.ЗаписатьАтрибут("Пользователь", ЗначениеВСтрокуВнутр(Строка.Пользователь));
ЗаписьХМЛ.ЗаписатьАтрибут("ИмяОбъекта",ЗначениеВСтрокуВнутр(Строка.ИмяОбъекта));
ЗаписьХМЛ.ЗаписатьАтрибут("НаименованиеНастройки",ЗначениеВСтрокуВнутр(Строка.НаименованиеНастройки));
ЗаписьХМЛ.ЗаписатьАтрибут("СохраненнаяНастройка", ЗначениеВСтрокуВнутр(Строка.СохраненнаяНастройка));
ЗаписьХМЛ.ЗаписатьАтрибут("ИспользоватьПриОткрытии", ЗначениеВСтрокуВнутр(Строка.ИспользоватьПриОткрытии));
ЗаписьХМЛ.ЗаписатьАтрибут("СохранятьАвтоматически", ЗначениеВСтрокуВнутр(Строка.СохранятьАвтоматически));
ЗаписьХМЛ.ЗаписатьКонецЭлемента();
Потом считываю в другой базе:
ЧтениеХМЛ = Новый ЧтениеXML;
ЧтениеХМЛ.ОткрытьФайл("D:\doc.xml");
Пока ЧтениеХМЛ.Прочитать() Цикл
Если ЧтениеХМЛ.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если ЧтениеХМЛ.Имя = "Корневой" Тогда
Продолжить;
КонецЕсли;
Строка = тз.Добавить();
Строка.Пользователь = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("Пользователь"));
Строка.ИмяОбъекта = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("ИмяОбъекта"));
Строка.НаименованиеНастройки = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("НаименованиеНастройки"));
Строка.СохраненнаяНастройка = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("СохраненнаяНастройка"));
Строка.ИспользоватьПриОткрытии = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("ИспользоватьПриОткрытии"));
Строка.СохранятьАвтоматически = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("СохранятьАвтоматически"));
Выдает ошибку:
: Ошибка при вызове метода контекста (ЗначениеИзСтрокиВнутр)
Строка.СохраненнаяНастройка = ЗначениеИзСтрокиВнутр(ЧтениеХМЛ.ПолучитьАтрибут("СохраненнаяНастройка"));
по причине:
Ошибка преобразования
по причине:
Ошибка формата потока
Через Пакеты XDTO ты описываешь свои данные. Данные могут быть как структурой так и массивом или списком структур или примитивных типов.
Для того что бы создать массив нужно указать минимальное количество 0, максимальное количество размер массива, для списка это -1. Ну и выдумать свое пространство имен. Все достаточно просто.
А ты обычным чтение XML пройдись, а сериализатору подсовывай не весь файл, а только данные относящиеся к одному объекту. Объект может быть списком.
еще я чет не понял - нафик я создаю сериализатор, если все равно пользуюсь только Сериализатор.ФабрикаХДТО?
Не СписокОбъектов.Добавить посмотри в отладчике какие у СписокОбъектов свойчтва. Сейчас сам посмотрю тже
по причине:
Несоответствие типов XDTO:
Тип 'TypeDescription' не найден
Значение не может быть установлено свойству, имеющему объектный тип
напоролся
по причине:
по причине:
Ошибка преобразования данных XDTO:
Чтение объекта типа: Array - [7,16]
Проверка дополнительного свойства:
имя: Value
по причине:
Ошибка преобразования данных XDTO:
Чтение объекта типа: CatalogObject.усНоменклатура - [16,3]
Проверка дополнительного свойства:
имя: БазоваяЕдиницаХранения
по причине:
Ошибка отображения типов:
Отображение лексического значения '' в значение типа 'СправочникСсылка.усЕдиницыХранения'
по причине:
чего то снова не хваатет?
(68)Не правильно. Не точно мысль выражена.
Для объектов справочника в xml данных, должны быть все реквизиты которые определены для объекта с учетом значения предопределенного реквизита ЭтоГруппа. Реквизиты могут быть определены для групп и для элементов по-разному. Это никак не отражается в xml-схеме, но это влияет на сериализацию и успешность десериализации.
В сериализации первого объекта в массиве видно что это группа (
1)они все определены для группы?
2)пустые значения (в понятиях 1С значения по умолчанию) не всегда могут быть представлены просто пустой строкой, например xml-предствление пустой ссылки - это вовсе не пустая строка (если БазоваяЕдиницаХранения это ссылочный тип, то должно быть 00000000-0000-0000-0000-000000000000).
по причине:
Несоответствие свойства и элемента данных XDTO:
Свойство: 'ТипТранспортнойЕдиницы'
на момент установки это свойство неопределено
Ты эксортируй пакеты в выгружаемую конфигурацию из загружаемой. Тогда заполнение должно пройти нормально и загрузка.
(70)почему CatalogObject.усТипыТранспортныхЕдиниц?
там не может быть CatalogObject, там должен быть CatalogRef
Ну и вообще в целом в Array выгружать все это вовсе не обязательно. Можно выгружать в корневой элемент с любым именем, а потом просто читать сериализатором последовательно уже в объекты, как написано в (28).
(74) фабрика в моей конфиге создается по хмл-схеме приемника
(73) при попытке создать ref - получаю вместо ссылки Неопределено, так хоть объект создается
(75) да я хочу без лишнего класса, через фабрику )
при попытке загрузки
имя: БазоваяЕдиницаХранения
по причине:
Ошибка отображения типов:
Отображение лексического значения '' в значение типа 'СправочникСсылка.усЕдиницыХранения'
по причине:
(75) С эрраем то проще читать. Меньше буковок нажимать. Он для выгрузки использует родной сериализатор, а по уму должен заполнять объекты из пакета в экспортируемую конфигурацию
Читайте также: