Сериализация больших таблиц значений в 1С8

Рассмотрена специфика и предложена конкретная методика сериализации в файл больших таблиц значений.

Введение в проблему

В моей задаче необходимо было сохранять таблицу значений в файл. Но при большой нагрузке на сервер приложений таблица не сериализировалась через ЗначениеВСтрокуВнутр.

Методика, предложенная в http://kb.mista.ru/2/doku.php?id=1c:v8:howto:serializacija_tablicyznachenij_v_xml, не работает в 1с81 (8.1.15.14), видимо,  в более ранних версиях платформы это не возможно.

Если упаковать таблицу значений в хранилище значений, то методика работает:
ХЗ = Новый ХранилищеЗначений(ТЗ);

Однако, проблема заключалась в том, что при критической нагрузке и в хранилище значений 1С не могла упаковать таблицу значений, выдавала ошибку о нехватке памяти.

Решение

Решение нужно было написать быстро, и скорость чтения таблиц не должна была бы сильно пострадать. Скорость записи была не принципиальна.

Решено было таблицу пробовать выгружать обычным методом, а если ЗначениеВСтрокуВнутр выдаст ошибку, выгружать построчно.

Соответственно, при восстановлении таблицы проверялся формат файла, и в зависимости от формата использовалась та или иная распаковка.

Пример работы:

 

Код по упаковке в модуле САП:

 

Функция ТЗВТекст(ТЗ) Экспорт

       Попытка

             Т = Новый ТекстовыйДокумент();

             Т.УстановитьТекст(ЗначениеВСтрокуВнутр(ТЗ));

             Возврат Т;

       Исключение

             Возврат ТЗВТекстЧерезСтроки(ТЗ);

       КонецПопытки;

КонецФункции

 

Функция ТЗИзТекста(ТекстовыйДокумент) Экспорт

      

       Если ТекстовыйДокумент.ПолучитьСтроку(1) = "LINE_FORMAT" Тогда

             Возврат ТЗИзТекстаЧерезСтроки(ТекстовыйДокумент);

       КонецЕсли;

      

       Возврат ЗначениеИЗСтрокиВнутр(ТекстовыйДокумент.ПолучитьТекст());

КонецФункции

 

Функция ТЗВТекстЧерезСтроки(ТЗ) Экспорт

       Т = Новый ТекстовыйДокумент();

       МассивКолонок = Новый Массив();

       ВсегоКолонок = ТЗ.Колонки.Количество()-1;

       Для Инд = 0 По ВсегоКолонок Цикл

             МассивКолонок.Добавить(0);

       КонецЦикла;

      

       Т.ДобавитьСтроку("LINE_FORMAT");

      

       ТЗ2 = ТЗ.СкопироватьКолонки();

      

       РезСтрока = ЗначениеВСтрокуВнутр(ТЗ2);

       РезСтрока = ЭкранироватьСимволы(РезСтрока);

       Т.ДобавитьСтроку(РезСтрока);

 

      

       Для Каждого Строка ИЗ ТЗ Цикл

             Для Инд = 0 По ВсегоКолонок Цикл

                    МассивКолонок[Инд] = Строка[Инд];

             КонецЦикла;

             РезСтрока = ЗначениеВСтрокуВнутр(МассивКолонок);

             РезСтрока = ЭкранироватьСимволы(РезСтрока);

             Т.ДобавитьСтроку(РезСтрока);

       КонецЦикла;

       Возврат Т;

КонецФункции

 

Функция ТЗИзТекстаЧерезСтроки(ТекстовыйДокумент) Экспорт

       ИсхСтрока = РазЭкранироватьСимволы(ТекстовыйДокумент.ПолучитьСтроку(2));

       ТЗ = ЗначениеИзСтрокиВнутр(ИсхСтрока);

       ВсегоКолонок = ТЗ.Колонки.Количество()-1;

       Для Инд = 3 По ТекстовыйДокумент.КоличествоСтрок() Цикл

             ИсхСтрока = РазЭкранироватьСимволы(ТекстовыйДокумент.ПолучитьСтроку(Инд));

             Массив = ЗначениеИзСтрокиВнутр(ИсхСтрока);

             НСтр = ТЗ.Добавить();

             Для КолИнд = 0 По ВсегоКолонок Цикл

                    НСтр[КолИнд] = Массив[КолИнд];

             КонецЦикла;

       КонецЦикла;

      

       Возврат ТЗ;

      

КонецФункции

 

Функция ЭкранироватьСимволы(Строка)

       Р = СтрЗаменить(Строка, "\", "\\");

       Р = СтрЗаменить(Р, Символы.ПС, "\n");

       Р = СтрЗаменить(Р, Символы.ВК, "\r");

       Р = СтрЗаменить(Р, Символы.Таб, "\t");

      

       Возврат Р;

КонецФункции

 

Функция РазЭкранироватьСимволы(Строка)

       Р = СтрЗаменить(Строка, "\\", "\");

       Р = СтрЗаменить(Р, "\n", Символы.ПС);

       Р = СтрЗаменить(Р, "\r", Символы.ВК);

       Р = СтрЗаменить(Р, "\t", Символы.Таб);

       Возврат Р;

КонецФункции

 

Пример использования кода:

Функция СохранитьРасчет(ИмяФайла, Таблица) Экспорт

       Попытка

             Значение = ЗначениеВСтрокуВнутр(Таблица);

             Т = Новый ТекстовыйДокумент();

             Т.УстановитьТекст(Значение);

             Т.Записать(ИмяФайла, "UTF-8");

            

             Возврат ИмяФайла;

       Исключение

             ОписаниеОшибки = ОписаниеОшибки();

             Сообщить("Не смогли преобразовать таблицу для сохранения в файл: " + ИмяФайла +  "  " + ОписаниеОшибки + ". Будем записывать в другом формате.", СтатусСообщения.Важное);

            

             Т = САП.ТЗВТекст(Таблица);

             Т.Записать(ИмяФайла, "UTF-8");

       КонецПопытки;

      

КонецФункции

 

 

Функция ВосстановитьРасчет(ИмяФайла) Экспорт

       Попытка

             Т = Новый ТекстовыйДокумент();

             Т.Прочитать(ИмяФайла, "UTF-8");

             Значение = САП.ТЗИзТекста(Т);

       Исключение

             Возврат Неопределено;

       КонецПопытки;

       Возврат Значение;

      

КонецФункции

Пример тестирования функции:

  ТЗ = новый ТаблицаЗначений;

  ТЗ.Колонки.Добавить("Кол1");

  ТЗ.Колонки.Добавить("Кол2");

 

  Стр = ТЗ.Добавить();

  Стр.Кол1 = 1;

  Стр.Кол2 = "1";

 

  Стр = ТЗ.Добавить();

  Стр.Кол1 = 2;

  Стр.Кол2 = "2";

 

 

 

  ТД = САП.ТЗВТекстЧерезСтроки(ТЗ);

  Сообщить(ТД.ПолучитьТекст());

  ТЗ = САП.ТЗИзТекстаЧерезСтроки(ТД);

  ТЗ.ВыбратьСтроку();