gifts2017

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

Опубликовал Осипов Сергей (fixin) в раздел Программирование - Практика программирования

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

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

Методика, предложенная в 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";

 

 

 

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

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

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

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


 

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Василий Антонов (khaoos) 26.09.12 05:16
А какова разница по скорости упаковки/распаковки обычного метода и построчного на больших таблицах? Если не очень существенная, то я бы не давал шанса обычному методу вывалить ошибку о нехватке памяти (если эта ошибка конечно не быстро вываливается). Или все же имеет смысл разделять использование методов в зависимости от ситуации?
2. Андрей Казанцев (ander_) 26.09.12 07:40
(1) khaoos, осмелюсь предположить, что разница в скорости будет в несколько раз.
3. Осипов Сергей (fixin) 26.09.12 08:01
(2) не замерял, но думаю, что стандартный метод работает гораздо быстрее
4. Александр Орефков (orefkov) 26.09.12 09:22
Имхо, чем выгружать построчно, да еще перебирая все колонки в цикле, можно используя метод Скопировать ТаблицыЗначений, выдергивать по 1000 строк в другую ТЗ, и сохранять ее.
artbear; fixin; +2 Ответить 1
5. Осипов Сергей (fixin) 26.09.12 11:28
(4) да, согласен, будет работать быстрее, но мне нужно было сделать затычку для защиты от переполнения памяти. Переделывать уже не буду.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа