У меня случилась неприятность – в личной базе данных полетела колонка с текстом в таблице, где хранились сообщения, накопленные в почтовой переписке за 5 лет. После запуска CHDBFL текст сообщений исчез во всей таблице, в каждой ее записи!
Всё остальное не пострадало. Я решил не восстанавливать базу из архива (с потерей последних нескольких дней), а ручками перенести тексты из бэкапа. Об этом этюд. Он будет полезен в плане демонстрации ручных навыков работы с XML.
Сообщения хранились в документе пимСообщение. В нем было всего две колонки для текста сообщения:
Соответственно, нужно было восстановить только два этих поля.
Сообщений было 500 000. Стандартная ВыгрузкаЗагрузкаДанныхЧерезXML от 1С не справилась, написала – не хватает памяти.
Перенести нужно было быстро. Поэтому решил писать свой код, а не муторно искать готовое решение.
Код работает быстро, т.к. не загромождает память. Просто выполняет выгрузку, чтение и запись.
Код выполняю непосредственно в консоли кода.
Код по выгрузке выглядит так:
З = Новый Запрос("ВЫБРАТЬ Ссылка, ШаблонСообщения ИЗ Документ.пимСообщение");
Выборка = З.Выполнить().Выбрать();
ИмяФайла = "R:\1.xml";
ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайла, "windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("items");
Сч = 0;
Пока Выборка.Следующий() Цикл
Сч = Сч + 1;
Если Сч % 100 = 0 Тогда
Состояние("" + Сч + " из " + Выборка.Количество());
КонецЕсли;
ЗаписьXML.ЗаписатьНачалоЭлемента("item");
ЗаписьXML.ЗаписатьНачалоЭлемента("link");
ЗаписьXML.ЗаписатьТекст(ЗначениеВСтрокуВнутр(Выборка.Ссылка));
ЗаписьXML.ЗаписатьКонецЭлемента();
Попытка
Значение = Выборка.Ссылка.Текст;
ЗаписьXML.ЗаписатьНачалоЭлемента("text");
ЗаписьXML.ЗаписатьТекст(Значение);
ЗаписьXML.ЗаписатьКонецЭлемента();
Исключение
КонецПопытки;
Попытка
Значение = ЗначениеВСтрокуВнутр(Выборка.Ссылка.ТекстХран);
ЗаписьXML.ЗаписатьНачалоЭлемента("texth");
ЗаписьXML.ЗаписатьТекст(Значение);
ЗаписьXML.ЗаписатьКонецЭлемента();
Исключение
КонецПопытки;
ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
Код по загрузке выглядит так:
ЧтениеXML = Новый ЧтениеXML();
ИмяФайла = "R:\1.xml";
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Сч = 0;
ТекОбъект = Неопределено;
Пока ЧтениеXML.Прочитать() Цикл
Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
//Сообщить("" + ЧтениеXML.ТипУзла + ":" + ЧтениеXML.Имя );
Если ЧтениеXML.Имя = "item" Тогда
Сч = Сч + 1;
Если Сч % 100 = 0 Тогда
Состояние(Сч);
КонецЕсли;
Если ТекОбъект <> Неопределено Тогда
ТекОбъект.Записать();
//Сообщить(ТекОбъект);
КонецЕсли;
ТекОбъект = Неопределено;
ИначеЕсли ЧтениеXML.Имя = "link" Тогда
ЧтениеXML.Прочитать();
ТекСсылка = ЗначениеИзСтрокиВнутр(ЧтениеXML.Значение);
ТекОбъект = ТекСсылка.ПолучитьОБъект();
ИначеЕсли ЧтениеXML.Имя = "text" Тогда
ЧтениеXML.Прочитать();
Если ТекОбъект <> Неопределено Тогда
ТекОбъект.Текст = ЧтениеXML.Значение;
КонецЕсли;
ИначеЕсли ЧтениеXML.Имя = "texth" Тогда
ЧтениеXML.Прочитать();
ТекЗначение = ЗначениеИзСтрокиВнутр(ЧтениеXML.Значение);
//Сообщить("" + ТекОбъект + "" + ТекЗначение);
Если ТекОбъект <> Неопределено Тогда
ТекОбъект.ТекстХран = ТекЗначение;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ТекОбъект <> Неопределено Тогда
ТекОбъект.Записать();
//Сообщить(ТекОбъект);
КонецЕсли;
ЧтениеXML.Закрыть();