Алхимическое использование хранилища значений - работа с внутренним форматом вторым способом

10.12.25

Разработка - Механизмы платформы 1С

В статье рассмотрено использование хранилища значения как всеядной альтернативы функций внутреннего формата.

Введение

Общеизвестный факт, что для обменов можно использовать следующие способы:

  1. Хранение через формат xml. Поддерживается всеми версиями 1С 8.х практически для всех объектов. Разве что некоторое время назад 
  2. Хранение через json. Более новый формат хранения данных в виде стоки.
  3. Хранение через внутренний формат данных. Формат использовался в 1С 7.7 и продолжает использоваться, хотя уже в меньшей степени для 1С 8.х. 

Однако, для хранения данных пригодно не только хранение в этих форматах, но и сам тип ХранилищеЗначений. В этой статье детально рассмотрен алхимический способ работы с типом хранилище значений, чтобы получить внутренний формат на языке 1С даже на мобильных устройствах.

 

Краткие сведения о типе и работе с ним из Документации

Тип появился в платформе 1С 8.0, поддерживается на всей линейке 1С 8.х на компьютерных и мобильных устройствах, имеет основные методы:

  1. Получить() - для восстановления сохраненных данных.
  2. Конструктор новый  ХранилищеЗначений(Значение).

Пункты 1 и 2 пригодны для типов данных, которые позволяют выполнить сериализацию данных плюс использование типа РезультатЗапроса, который тоже можно сохранить в Хранилище и потом успешно восстановить.

Но здесь ключевой момент с точки зрения алхимии разработки - сам тип способен конвертироваться в base64 строку, что позволяет проводить над самим типом и его значением нестандартные операции.

 

Хранилище значений - взгляд алхимика

Поскольку хранилище значений можно превратить в base64 строку, то это позволяет выгрузить его содержимое целиком в файл. Для этого можно использовать следующий код:

	ТМП = ПолучитьИмяВременногоФайла("txt");
	Тер = XMLЗначение(Тип("ДвоичныеДанные"),XMLСтрока(новый ХранилищеЗначения(ЗначениеКонвертации)));
	Тер.Записать(ТМП);

Скриншот содержимого получившегося файла для хранилища без сжатия выглядит таким образом:

 

 

Получается, что хранилище значений вызывает встроенную функцию сериализации во внутренний формат 1С (подробнее про описание формата здесь)!!! А это означает, что во внутренний формат 1С можно выгрузить и загрузить данные целиком через тип ХранилищеЗначений, и так как сие типы поддерживаются и мобильной платформой, то можно реализовать работу с  внутренним форматом 1С на мобильной платформе без внешних компонент!!!

 

Базовые функции и процедуры для реализации

Поскольку хранилище значений, имеет размер спецификации в 13 впереди стоящих символов и сохраненное ранее значение - это позволяет сделать следующие операции:

  1. Выгрузить пригодные к сериализации типы данных по технологии внутреннего формата данных.
  2. Восстановить значения из внутреннего формата 1С через предварительную конвертацию данных.

Любое значение во внутренний формат при помощи следующий функции:

функция _ЗначениеВСтрокуВнутрМобильник(ЗначениеКонвертации)	
	ТМП = ПолучитьИмяВременногоФайла("txt");
	Строка1 = Преобразовать64(XMLСтрока(новый ХранилищеЗначения(ЗначениеКонвертации))); 
	// Вычислить спецификацию Хранилища Значений в формате XML без сжатия:
	Размер=13;
	Пока Размер>0 Цикл Строка1.Удалить(0); Размер=Размер-1; КонецЦикла;
	//Теперь осталось это превратить в нормальный тип данных - самое тупое просто через
	// двоичку конвертировать!!!
	Тер = XMLЗначение(Тип("ДвоичныеДанные"),Преобразовать64(,Строка1));
	Тер.Записать(ТМП);
	//Достаем сохраненные данные из спецификации:
	Текст = новый ЧтениеТекста(ТМП);
	Содержимое=Текст.Прочитать();
	Текст.Закрыть();
	УдалитьФайлы(ТМП);
	Возврат Содержимое;	
КонецФункции

Данный способ позволяет неявно вызвать сериализацию внутреннего формата и таким образом легко сохранить нужные типы данных.

А вот восстановить значение из этого формата таким способом, гораздо сложнее, тем не менее возможно.

Алгортм следующий:

  1. Если тип простой - восстановливать через хранилище значений.
  2. Сложные коллекции и типы - разобрать до простых и поэтапно восстанавливать. 

Для этого нужно предварительно загрузить в хранилище шаблон значения, а уже потом приделав к нему спецификацию 13 символов и скорректировать адрес обращения удастся восстановить значение.

Восстановить простое значение можно только через некоторое значение образец:

функция _ЗначениеИзСтрокиВнутрМобильник(ЗначениеОбразец,ЗначениеКонвертации)		
	//Все делаем но наоборот!!!
	ТМП = ПолучитьИмяВременногоФайла("txt");
	Текст = новый ЗаписьТекста(ТМП);
	Текст.Записать(ЗначениеКонвертации);
	Текст.Закрыть();
	ОБ_ДД=Новый ДвоичныеДанные(ТМП);
	МассивБезСпецификации = Преобразовать64(XMLСтрока(ОБ_ДД)); 
	//Образец для генерации спецификации хранилища значений!!! - без неё исходное не восстановить!!!
	ШаблонХранилища_XML=   XMLСтрока(новый ХранилищеЗначения(ЗначениеОбразец));
	МассивСпецификации = Преобразовать64(ШаблонХранилища_XML); 
	Размер=13;  
	Ид=0;
	Пока Ид<Размер Цикл МассивБезСпецификации.Вставить(Ид,МассивСпецификации[Ид]); Ид=Ид+1; КонецЦикла;
    //Теперь  в Хранилище значения и достаем!!!
	XML_СтруктураТипа =    Преобразовать64(,МассивБезСпецификации);
	//Поскольку парсер иногда косячит - сдвигает лишние плсюы и прочее - нужно сделать следующее:
	 //7v3 - это начало значения поиска!!!
	Дескриптор = Лев(ШаблонХранилища_XML,Найти( ШаблонХранилища_XML,"7v3")-1);
	XML_СтруктураТипа =   Дескриптор+Сред(XML_СтруктураТипа, Найти( XML_СтруктураТипа,"7v3"));
	Хранилище=XMLЗначение(Тип("ХранилищеЗначения"),XML_СтруктураТипа);
	УдалитьФайлы(ТМП);
    возврат Хранилище.Получить();
КонецФункции

 

Предостережение:

Если допустить ошибку с шаблоном значения при восстановлении через хранилище, то 1С потом не сможет верно преобразовать значение, и получите сообщение о ошибке формата потока в лучшем случае, в худшем случае придется перезапустить сеанс.

На практике поэтому рекомендация: 

  1. Восстанавливать значения таким образом: сначала восстанавливается тип, а потом проверяется - имеются ли в системе методы его обработки. 
  2. Если тип не простой (коллекция, структура) и нет возможности восстановить элемент - лучше вернуть Неопределено и сохранить работоспособность, предварительно выдав уведомление что такой тип невозможно восстановить.

Для тестирования этих функций используется следующий код:

    СсылкаКонец = Справочники.Банки.ПолучитьСсылку(новый УникальныйИдентификатор);
	СсылочныйТип=ЭтотОбъект.Метаданные().Реквизиты.ТипЛюбаяСсылка.Тип.Типы();
	Если СсылочныйТип.Количество()=0 или СсылочныйТип.Количество()=1 Тогда  
        Сообщить("Нет ссылок для тестирования!!!"); 
        Возврат; 
    КонецЕсли;	 
	СсылкаКонец = новый(СсылочныйТип[1]);
	Сообщить("--Тест алгоритма в строку--");
	Тест1 = ЗначениеВСтрокуВнутр(СсылкаКонец);
	Содержимое=_ЗначениеВСтрокуВнутрМобильник(СсылкаКонец);
	Сообщить(Тест1);
	Сообщить(Содержимое);
	Сообщить(Содержимое=Тест1);
	Сообщить("--Тест алгоритма из строки--");
	Тест1 = ЗначениеИзСтрокиВнутр(Содержимое);
    //Тестирование типов данных:
	Содержимое1=_ЗначениеИзСтрокиВнутрМобильник(ТипЗнч(Тест1),"{""T"",51e7a0d2-530b-11d4-b98a-008048da3034}");
	Содержимое=_ЗначениеИзСтрокиВнутрМобильник(СсылкаКонец,Содержимое);
	Сообщить(Тест1);
	Сообщить(Содержимое1);
	Сообщить(Содержимое);
	Сообщить(Содержимое=Тест1);

 

Постскриптум:

Используемые методы позволяют на 90% перенести функционал работы с внутренним форматом на мобильную платформу, и тем самым улучшить совместимость прикладных решений на мобильных устройствах.

Отдельная благодарность автору функции Преобразовать64 благодаря которой , можно решать не один класс задач на такие строки.

Для сохранения целостности изложения результатов, просто продублирую функцию из публикации.

&НаСервере
Функция Преобразовать64(Строка64 = неопределено, Массив64 = неопределено)
 Таб64 = Новый ТаблицаЗначений;
 Таб64.Колонки.Добавить("Код");
 Таб64.Колонки.Добавить("Символ");
 Нпп = 0;
 Для Код = КодСимвола("A") По КодСимвола("Z") Цикл
  стр = Таб64.Добавить();
  стр.Код = Нпп;
  стр.Символ = Символ(Код);
  Нпп = Нпп + 1;
 КонецЦикла;
 Для Код = КодСимвола("a") По КодСимвола("z") Цикл
  стр = Таб64.Добавить();
  стр.Код = Нпп;
  стр.Символ = Символ(Код);
  Нпп = Нпп + 1;
 КонецЦикла;
 стр = Таб64.Добавить();
 стр.Код = Нпп;
 стр.Символ = "0";
 Нпп = Нпп + 1;
 Для Код = 1 По 9 Цикл
  стр = Таб64.Добавить();
  стр.Код = Нпп;
  стр.Символ = Формат(Код,"ЧЦ=1; ЧДЦ=0");
  Нпп = Нпп + 1;
 КонецЦикла;
 стр = Таб64.Добавить();
 стр.Код = Нпп;
 стр.Символ = "+";
 Нпп = Нпп + 1;
 стр = Таб64.Добавить();
 стр.Код = Нпп;
 стр.Символ = "/";
 
 Если Массив64 = неопределено Тогда 
  Если Строка64 = неопределено Тогда
   Сообщить("неверный вызов функции");
   Возврат неопределено;
  КонецЕсли;
  //Уберем переносы строк
  Строка64 = СтрЗаменить(Строка64, Символ(10), "");
  Строка64 = СтрЗаменить(Строка64, Символ(13), "");
  
  //преобразовываем строку в массив
  Если СтрДлина(Строка64) % 4 <> 0 Тогда
   Сообщить("длина строки на входе должна быть кратна 4"); 
   Сообщить(СтрДлина(Строка64)); 
   Возврат неопределено;
  КонецЕсли;
  Кол4 = Цел(СтрДлина(Строка64) / 4);
  РазмерМ = Кол4 * 3;
  Если Прав(Строка64, 2) = "==" Тогда
   РазмерМ = РазмерМ - 2;
  ИначеЕсли Прав(Строка64, 1) = "=" Тогда
   РазмерМ = РазмерМ - 1;
  КонецЕсли;   
  Массив64 = Новый Массив(РазмерМ);
  Для А = 1 По Кол4 Цикл
   Число3 = 0;
   Для Б = 1 По 4 Цикл
    Буква1 = Сред(Строка64, (А-1)*4 + Б, 1); 
    Если Буква1 = "=" Тогда
     Код4 = 0;
    Иначе
     стрН = Таб64.Найти(Буква1, "Символ");
     Если стрН = Неопределено Тогда
      Сообщить("ошибка при поиске "+ КодСимвола(Буква1)); 
     Иначе 
      Код4 = стрН.Код;
     КонецЕсли;
    КонецЕсли;
    Число3 = Число3 * 64 + Код4;
   КонецЦикла;
   Ост = Число3 % 256;
   Индекс = (А-1)*3 + 2;
   Если Индекс <= РазмерМ - 1 Тогда
    Массив64[Индекс] = Ост;
   КонецЕсли;
   Число3 = (Число3 - Ост) / 256;
   Ост = Число3 % 256;
   Индекс = (А-1)*3 + 1;
   Если Индекс <= РазмерМ - 1 Тогда
    Массив64[Индекс] = Ост;
   КонецЕсли;
   Число3 = (Число3 - Ост) / 256;
   Ост = Число3 % 256;
   Массив64[(А-1)*3 + 0] = Ост;
  КонецЦикла;
  Возврат Массив64;
 Иначе //Преобразовываем массив в строку
  Строка64 = "";
  Кол3 = Цел(Массив64.Количество() / 3);
  Если Массив64.Количество() % 3 <> 0 Тогда
   Кол3 = Кол3 + 1;
  КонецЕсли;
  Для А = 1 По Кол3 Цикл
   Число3 = Массив64[(А-1)*3]; 
   Если (А-1)*3+1 <= Массив64.ВГраница() Тогда
    Код3 = Массив64[(А-1)*3+1];
   Иначе
    Код3 = 0;
   КонецЕсли;
   Число3 = Число3*256 + Код3;
   Если (А-1)*3+2 <= Массив64.ВГраница() Тогда
    Код3 = Массив64[(А-1)*3+2];
   Иначе
    Код3 = 0;
   КонецЕсли;
   Число3 = Число3*256 + Код3;
   
   Ост4 = Число3 % 64;
   Число3 = (Число3 - Ост4) / 64;
   Ост3 = Число3 % 64;
   Число3 = (Число3 - Ост3) / 64;
   Ост2 = Число3 % 64;
   Число3 = (Число3 - Ост2) / 64;
   Ост1 = Число3 % 64;
   Число3 = (Число3 - Ост1) / 64;
   стрН = Таб64.Найти(Ост1, "Код");
   Если стрН = неопределено Тогда
    Сообщить("Ошибка при поиске");
   Иначе
    Строка64 = Строка64 + стрН.Символ;
   КонецЕсли;
   стрН = Таб64.Найти(Ост2, "Код");
   Если стрН = неопределено Тогда
    Сообщить("Ошибка при поиске");
   Иначе
    Строка64 = Строка64 + стрН.Символ;
   КонецЕсли;
   стрН = Таб64.Найти(Ост3, "Код");
   Если стрН = неопределено Тогда
    Сообщить("Ошибка при поиске");
   Иначе
    Строка64 = Строка64 + стрН.Символ;
   КонецЕсли;
   стрН = Таб64.Найти(Ост4, "Код");
   Если стрН = неопределено Тогда
    Сообщить("Ошибка при поиске");
   Иначе
    Строка64 = Строка64 + стрН.Символ;
   КонецЕсли;
  КонецЦикла;
  //Если количество символов не делится на 3, то на конце должны быть
  //знаки "="
  Если Массив64.Количество() % 3 = 1 Тогда
   Строка64 = Лев(Строка64, СтрДлина(Строка64)-2)+ "=="; 
  ИначеЕсли Массив64.Количество() % 3 = 2 Тогда
   Строка64 = Лев(Строка64, СтрДлина(Строка64)-1)+ "="; 
  КонецЕсли;
  Возврат Строка64;
 КонецЕсли;

 

Вступайте в нашу телеграмм-группу Инфостарт

Хранилище значений мобильная платформа внутренний формат 1С алхимик разработки.

См. также

Механизмы платформы 1С Программист Бесплатно (free)

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

16.07.2025    24716    TitanLuchs    106    

144

Механизмы платформы 1С Работа с интерфейсом Программист Стажер 1С:Предприятие 8 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    13659    bayselonarrend    127    

67

Механизмы платформы 1С Программист 1С:Предприятие 8 Бесплатно (free)

В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.

30.01.2025    14724    user2122906    9    

60

Механизмы платформы 1С WEB-интеграция Программист 1С:Предприятие 8 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    25002    dsdred    77    

142

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    23224    bayselonarrend    22    

172

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    12886    dsdred    22    

85
Для отправки сообщения требуется регистрация/авторизация