Преобразовать хранилище значений в строку 1с
Важное замечание в начале. Основной режим работы 1С в этой статье предполагается 1С 8.3.7 в режиме тонкого клиента без модальных вызовов — самый современный на настоящий момент, на который вскоре должны быть переведены все конфигурации. Также постараюсь описать особенности работы в Веб-Клиенте.
Что такое двоичные данные и как с ними можно работать в 1С 8
Двоичные данные (или бинарные) — это файл данных произвольного формата.
Платформа 1С (8.3 и 8.2) в общем случае понятия не имеет, что это. Предполагается, что программист или пользователь знает, какие именно это данные и как их применять. Тем не менее, если в двоичные данные загружен графический файл, формат которого понимает объект типа «Картинка», то при инициализации картинки такими двоичными данными картинка будет нормально показана, а её свойство «Формат» примет правильное значение.
Платформа 1С при работе с двоичными данными может:
Возможно, я еще что-то упустил, однако интуитивно ясно, что практически все, что надо для работы с двоичными данными в 1С, у нас есть. Рассмотрим теперь по порядку несколько конкретных примеров работы с двоичными данными на платформе 1С 8.3.
Чтение и запись двоичных данных в файл
Основной тип объектов двоичных данных платформы 1С так и называется: «ДвоичныеДанные». Вот что говорит о нем «Синтаксис-помощник»:
Значение содержит двоичные данные, которые считываются из файла. Значение может быть сохранено в ХранилищеЗначения. Хранимые данные могут быть записаны в файл.
Доступность: Тонкий клиент, веб-клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение(клиент), мобильное приложение(сервер).
Сериализуется. Данный объект может быть сериализован в/из XML. Может использоваться в реквизитах управляемой формы.
Чтение двоичных данных из файла
Если вы только начинаете программировать в 1С или просто хотите систематизировать свои знания - попробуйте Школу программирования 1С нашего друга Владимира Милькина. Пошаговые и понятные уроки даже для новичка с поддержкой учителя.
Попробуйте бесплатно по ссылке >>
Тип «Двоичные данные» имеет единственный конструктор:
имяФайла — обязательный аргумент.
В итоге получаем программный объект двоичных данных, прочитанный из файла.
Запись двоичных данных в файл
Определение размера двоичных данных в байтах
Сохранение двоичных данных в реквизит объекта
Рассмотрим сразу запись двоичных данных из файла на клиенте в реквизит объекта базы данных типа ХранилищеЗначения. Причем напишем такой код, который сработает и на веб-клиенте, а также будет лишен модальных вызовов, то есть таких вызовов, которые ожидают действия пользователя и останавливают при этом исполнение программы. Теперь платформа 1С 8.3 требует разрабатывать асинхронные программы.
Выглядит это примерно так: создается обработчик оповещения о выполнении некоторой длительной процедуры, затем запускается процедура «НачатьХХХ()», в которую, кроме понятных аргументов, передается еще и описание обработчика ее завершения. Наша программа спокойно работает далее, а по завершении запущенной процедуры вызывается наш обработчик завершения.
Предположим, у нас на форме есть реквизит типа «СправочникСсылка.Картинки». Справочник «Картинки» имеет реквизит «ДанныеКартинки» типа ХранилищеЗначения.
Создадим команду формы «ЗагрузитьКартинкуИзФайла».
Создадим обработчик команды, выделив команду в списке команд формы и нажав на кнопку с увеличительным стеклом в поле «Действие» панели свойств:
Поскольку все необходимые параметры для записи картинки мы можем передать изнутри клиентской части обработчика, нам нет нужды создавать контекстную серверную процедуру на сервере. Выберем «Создать на клиенте и процедуру на сервере без контекста»:
Вначале напишем наши обработчики команды в старом, «модальном» или «синхронном» стиле:
В моей небольшой тестовой конфигурации этот код отлично сработал в режиме тонкого клиента. Теперь преобразуем модальный вызов «ПоместитьФайл» в асинхронный, он же немодальный. В меню конфигуратора запустим команду меню «Текст >Рефакторинг >Нерекомендуемые синхронные вызовы >Преобразовать вызовы модуля». Нам в ответ сообщат, что «Не рекомендуемых синхронных вызовов преобразовано: 1».
Для компактности я удалил все пустые строки, и вот что получилось вместо клиентской части нашего обработчика:
Готово! Мы кошерно асинхронно записали картинку из файла на клиенте в реквизит объекта базы данных, в нашем случае — элемента справочника.
Чтение двоичных данных из объекта БД
Для чего нам надо читать двоичные данные из объекта БД? Наверное, три самых частых случая таковы:
- Внедрить картинку в табличный документ, например, отчет. Табличный документ (отчет) часто формируется на стороне сервера, поэтому нам нет нужды гонять картинки через временное хранилище. Мы просто получаем значение из реквизита типа «хранилище значения», инициализируем им объект типа «Картинка» и помещаем эту картинку в табличный документ. А клиентская сторона приложения отображает уже сформированный табличный документ.
- Отобразить на форме некоторую картинку. Нам надо передать двоичные данные на сторону клиента и загрузить их в реквизит формы при открытии формы. Ну и желательно обновлять картинку по некоторым событиям.
- Сохранить двоичный файл на стороне клиента. Здесь надо получить данные с сервера по некоторой команде и просто сохранить их в файл на клиенте.
Пример 1. Вставить картинки в макет (табличный документ).
Допустим, у нас есть база данных со справочником «Картинки», у элементов которых есть реквизит «Картинка» типа ХранилищеЗначения, содержащий данные картинки.
Создадим новую внешнюю обработку, ее основную форму.
На форме создадим 3 реквизита «СпрКартинка1», «СпрКартинка2», «СпрКартинка3» типа «СправочникСсылка.Картинки» и реквизит «ТабДок» типа «ТабличныйДокумент». Перетащим мышкой эти реквизиты в список элементов формы, чтобы на ней образовались соответствующие поля.
Добавим команду формы «НапихатьКартинок» и создадим ее обработчик. На сей раз выберем «Создать на Клиенте и процедуру на сервере», чтобы не передавать много параметров в процедуру без контекста. Напишем такие обработчики:
И получим примерно такой результат:
Пример 2. Показать картинку из базы данных на форме.
Для демонстрации воспользуемся первой обработкой, где мы записывали файл в БД. Теперь покажем на форме картинку, которая записана в реквизите «Картинка» выбранного на форме элемента справочника «Картинки».
Во-первых, добавим на форму поле, связанное с реквизитом «АдресДанныхКартинки». Например, перетащим мышкой этот реквизит в список элементов формы. Выберем и установим значение свойства «Вид» этого поля в «Поле картинки».
Во-вторых, напишем такую серверную процедуру:
И станем вызывать эту процедуру, например, из обработчика события «При изменении» поля «Картинка»:
Сохранение двоичных данных в файл на клиенте
Думаю, с сохранением двоичных данных из базы данных в файл у Вас проблем не возникнет. По крайней мере, если Вы работаете не в веб-клиенте. Читаем, помещаем во временное хранилище на сервере, затем записываем в файл на клиенте.
Кодирование двоичных данных в формат Base64 и обратно
Тут все очень просто. Платформа имеет две глобальные функции, доступные везде:
- Base64Строка(<Значение>)
- Base64Значение(<Строка>)
Первая получает в качестве аргумента объект типа «ДвоичныеДанные», а возвращает его текстовое представление в кодировке base64, а вторая, наоборот, из текста в формате base64 возвращает объект типа «ДвоичныеДанные».
Итого
На самых простых примерах мы увидели все основные принципы и методы работы с двоичными данными в 1С 8.3. Также коснулись актуальной сейчас темы устранения синхронных вызовов. Остальные возможности работы с двоичными данными Вы без труда реализуете по аналогии с рассмотренными здесь.
Объект "ХранилищеЗначения" известен в 1С, начиная с 8.0 и, казалось бы, прост, понятен, изучен вдоль и поперёк. Но иногда возникают вопросы, касающиеся работы с хранилищем, и данная публикация (по сути, краткий антисклерозник) призвана зафиксировать ответы на некоторые из них.
Хранилище значения (далее ХЗ) представляет собой данные, полученные кодированием и, при необходимости, сжатием входных данных с помощью 32-х битного алгоритма // из строки в ХЗ хз=XMLЗначение(Тип("ХранилищеЗначения"),ИсходнаяСтрокаBase64); // из ХЗ в строку ИтоговаяСтрокаBase64=XMLСтрока(ХЗ);
Важно понимать, что ХЗ это не значение, а указатель на область памяти. Они всегда разные, поэтому ни сравнение, ни поиск, ни отбор (в т.ч. в запросах) применять нельзя. Указатель равен сам себе лишь в рамках конкретного оператора-конструктора (и, кстати, в этом случае по нему работает, например, поиск в универсальных коллекциях). Так, например, если "А=хз; Б=А;", то А будет равно Б. А для сравнения именно значений следует действовать так (причём это не будет распаковкой как "расжатием"):
и это не зависит от наличия и степени сжатия в их конструкторах. Кстати, после применения конструктора определить степень сжатия можно лишь преобразованием в двоичные данные и анализом первых битов потока.
Так вот, размер "как есть" мы можем узнать, либо создав объект метаданных (например, справочник с единственным реквизитом типа ХЗ) и получив размер таблицы методом ПолучитьРазмерДанныхБазыДанных, либо опосредованно, через строку и двоичные данные (учитывая неизбежно прибавляемое), так:
Это не годится для абсолютных замеров (так, один символ латиницы, т.е. по идее 1 байт, и символ кириллицы, 2 байта, дают одинаковые 32 байта на выходе), но годится для относительных прикидок. Так, вызов без прямого указания "СжатиеДанных" всегда даёт значение большего (и иногда существенно большего, в разы) размера, чем с любым сжатием. На малых размерах сжатие не даёт заметного эффекта при любом аргументе. В СП сказано, что аргумент по умолчанию для объекта "СжатиеДанных" равен 1, но сжатие без его указания и с явным указанием даёт разные размеры, до десятков и сотен байт. На средних объектах (например, строки 500-1000 символов) сжатие со степенью выше 3-4 даёт примерно одинаковые итоговые размеры, т.е. эффективность одинаковая. Наряду с этим, в ряде старых релизов конструктор без сжатия даёт меньший итоговый размер.
Деструкция этого указателя тоже имеет нюансы.
В таблицах/деревьях значений с явно объявленной колонкой может использоваться везде, кроме запроса (не помещается в ВТ), не воспринимается как аргумент запроса, даже как &ПараметрТипаХЗ в секции "ВЫБРАТЬ". Что, учитывая известное про СУБД, не вполне логично.
При копировании объекта с реквизитами, содержащими ХЗ, ни интерфейсно, ни программно, эти значения НЕ наследуются, не копируются.
Если некое значение, упакованное в ХЗ, подпадает под RLS, то логика следующая - платформа всегда вначале выполняет неявную распаковку, либо рассматривает сделанную в коде явную; а затем накладывает ограничение, так что RLS применится именно для уже распакованного значения, спровоцировать тут ошибку ни разу не удалось.
Из интересных публикаций рекомендую эту.
Поскольку в современных метаданных конфигураций реквизит типа ХЗ где-нибудь точно наличествует, а также фигурирует в коде, то вопрос занимаемого им места актуален. В связи с этим было бы интересно исследовать рост места, занимаемого таблицей, состоящей исключительно из ХЗ, а также сравнить эффективность работы "СжатиеДанных" и основанного на том же Deflation объекта "ЗаписьZipФайла", пробуя разные значения УровеньСжатияZIP (естественно, при МетодСжатияZIP = "Сжатие").
Возможно, этот привычный и вроде бы простой объект, Хранилище значения, преподнесёт (особенно на больших данных и нагрузках) ещё некоторые удивительные сюрпризы.
Есть динамически создаваемый объектный реквизит управляемой формы (например СправочникОбъект.Номенклатура). У него есть табличные части с реквизитами типа ХранилищеЗначения. Нужно предоставить пользователю возможность просматривать представления и редактировать содержимое этих хранилищ значений. Как оптимальнее всего решать такую задачу?
Пока я вижу только способ создания реквизита ТаблицаЗначений для каждой ТЧ с созданием дочерних реквизитов по колонкам ТЧ, но хранилища значений заменять на Строка(0). При чтении объекта помещать каждое хранилище значения во временное хранилище, а в реквизит таблицы помещать его адрес. Перед записью соответственно делать обратную процедуру. Но уж очень хлопотный способ.
Смириться или переделать архитектуру.
Сколько копий уже ломали, что хранилище значений в ТЧ - это зло.
(7) Форму то сделать проще простого. Как хранить хранилища значений для строк ТЧ (до записи объекта в базу)?
(6) Посмотри мой "Редактор объекта БД" из подсистемы "Инструменты разработчика". Там полная поддержка хранилищ значений (в ТЧ, в движениях, в реквизитах объекта).
не понимаю чем тут ТЗ поможет. как не крути ХЗ напрямую нельзя редактировать
(9) СправочникОбъект после редактирования ХЗ что мешает принудительно записать?
(12) хотя можно и не писать. только про модифицированность основной формы не забыть
получаешь ХЗ из ОБЪЕКТА на сервере, передаешь в форму редактирования параметром, ХЗ МОЖНО ПЕРЕДАВАТЬ, ОНО СЕРИАЛИЗУЕТСЯ, ПриСозданииНаСервере формы редактирования читаешь из ХЗ и помещаешь в реквизит формы
обратно передаешь так же: пакуешь реквизит в ХЗ и отдаешь как параметр оповещения
вот после этого надо по идее или взвести модифицированность основной формы или принудительно записать ОБЪЕКТ
Давайте сосредоточимся на (0). Платформа для реквизитов объектов типа ХранилищеЗначения реализует в серверном контексте формы внутреннее хранилище, т.е. на самом деле хранлища значений лежат в строках ТЧ данных формы на сервере, но они не видны в объектной модели и получить их нельзя. Если удалить строку ТЧ, то удалится и ее хранилище значения из серверных данных формы. Если переместить строку ТЧ, то у нее сохранится хранилище значения. При записи объекта все эти хранилища значений в реквизитах строк ТЧ появляются, но до этого момента их нельзя увидеть.
Поэтому я и написал в (0) что очевидным способом является реализованная на прикладном уровне альтернатива механизму платформы, но с возможностью получать хранилище значения ячейки на клиент и там редактировать его.
О! Можно же сериализовать в XML и как строку передавать.
Раз в 7 пожало. С учетом Base64 вроде норм. Но если есть альтернативы - буду рад узнать.
Хвосты одинэсной сериализации в ответе все же режут глаз :)
(4) ты у себя включишь, а кто то не включит. А потом переустановят и забудут включить.
(3) В мобильном приложении непонятно как разархивировать
(7) он привык работать во враждебной среде.
Когда админ 1снику волк
На уровне пакетов? А как уровень сжатия оценить? Если бы я мог убедиться, что жмёт не хуже - тогда имело бы смысл.
А так пока что мне проще один раз прописать в одном месте пару строк и получить железные гарантии.
В последнее время gzip активно применяется для сжатия интернет-трафика. Сейчас gzip поддерживают большинство современных браузеров
Так это,поток в памяти,это же и есть двоичные данные,а хранилище в него положить как раз через запись XML
(1) Не понял, ты хранилище значения сериализовал и отправил в мобильное приложение? В мобильном приложении разве доступно хранилище значения, или как ты его там преобразовал чтобы получить двоичные данные?
(23) Именно так. В мобильном приложении десериализовал и штатно извлек.
С документацией странная картина. В СП 18 релиза почему-то доступность для МП убрана. Хотя в СП 12 релиза поддержка МП еще прописана.
Похоже на ошибку в документации, ведь никто не убирал в МП возможность создавать реквизиты с таким типом.
Нет, дело не только в документации.
Использование конструктора ХранилищаЗначений в МП распознается как синтаксическая ошибка. Но конструктор при этом отрабатывает.
Ну, либо консерваторию сломали, либо хотели с ХранилищемЗначений на МП поступить как с ТаблицейЗначений на тонком клиенте. Ограничить непонятно что и непонятно зачем.
(27) Чтобы не гонять индексы с сервера на клиент и обратно
(16) сравнить размер json строки в utf-8 и количество переданных байт
(28) Это ты про ТЗ? А зачем их гонять? Переиндексировали бы по месту после десериализации. Да - объект тяжелый, использовать мол с осторожностью. Пару разъяснений на ИТС, как обычно. Но вводить чисто искусственное ограничение.
(29) Логично. Но подумав, мне все равно проще будет перестраховаться, даже если прозрачно жмется не хуже. Если был бы простой способ проверять с клиента работает ли прозрачное сжатие - можно было бы программно контролировать. А так у меня просто недостаточно уверенности что оно будет всегда работать.
Прочитай, хотя бы, Митичкина "Разработка в системе 1С:Предприятие 8". Волшебник
Читайте также: