Перенос реквизита типа ХранилищеЗначения между объектами, базами и файлами
Содержание
Чтобы скопировать хранилище значений в 1С внутри одной базы, достаточно присвоить реквизит: Приемник.Файл = Источник.Файл на сервере и записать объект-приёмник. Объект ХранилищеЗначения неизменяемый, поэтому общая ссылка на одно и то же хранилище ничего не ломает. Пересоздавать его через Новый ХранилищеЗначения(...) нужно только когда меняете степень сжатия или содержимое.
Сложности начинаются при переносе в другую базу или в файл. Внутри хранилища может лежать не только картинка или документ, но и структура со ссылками на справочники. Двоичные данные переносятся без потерь, а ссылки в чужой базе указывают в пустоту. От того, что лежит внутри, зависит способ копирования.
Что лежит в ХранилищеЗначения и когда его приходится копировать
ХранилищеЗначения — тип реквизита, в котором платформа хранит произвольное сериализуемое значение в упакованном виде. В таблице базы это одно поле неограниченной длины, а содержимое видно только после вызова метода Получить().
Что обычно кладут в такие реквизиты:
- 🖼️ картинки: фото номенклатуры, сканы, логотипы для печатных форм;
- 📎 файлы как
ДвоичныеДанные: PDF, xlsx, вложения писем; - 🧩 служебные данные: структуры, таблицы значений, настройки отчётов, сохранённые параметры обработок;
- 🔗 смешанное содержимое, где рядом с данными лежат ссылки на элементы справочников.
Типичные поводы для копирования:
- Нужно размножить элемент справочника вместе с картинкой или вложением.
- Данные переезжают из старой конфигурации в новую, и обмен не переносит нужный реквизит.
- Требуется выгрузить содержимое на диск: отдать файлы пользователю, разгрузить базу, сделать архив.
- Реквизит меняют на другой тип (например, файлы уходят в присоединённые файлы БСП), и старые данные надо переложить.
Не путайте с хранилищем конфигурации. Хранилище конфигурации — это отдельная база для групповой разработки, лежит в каталоге с файлом 1cv8ddb.1CD. Его копируют целиком папкой, когда к нему никто не подключён. Всё, что ниже, — про тип данных ХранилищеЗначения внутри информационной базы.
Способы копирования хранилища значений: какой выбрать
Выбор зависит от двух вопросов: куда переносите и есть ли внутри ссылки.
| Способ | Когда подходит | Риски |
|---|---|---|
| Присваивание реквизита на сервере | Копия внутри одной базы | Почти нет; важно записать приёмник |
Пересоздание через Получить() и Новый ХранилищеЗначения | Нужно другое сжатие или правка содержимого | Нагрузка на память при больших файлах |
Выгрузка ДвоичныеДанные в файл | Картинки и документы, перенос в любую базу | Теряется всё, кроме самих байтов |
Сериализация в XML (СериализаторXDTO) | Перенос между базами с одинаковой структурой | Ссылки внутри не перекодируются |
Выгрузка всей базы в .dt или копия через СУБД | Нужна полная копия со всеми хранилищами | Только целиком, выборочно не получится |
| Прямое копирование поля средствами SQL | Не рекомендуется | Внутренний формат, обход платформы и её проверок |
Интерактивное копирование элемента (кнопка «Скопировать» или F9) тоже создаёт новый объект на основании старого. Но перенос реквизита типа ХранилищеЗначения в этом сценарии зависит от того, как написана форма конкретной конфигурации. Если важно, чтобы картинка гарантированно ушла в копию, задайте это в коде (см. следующий раздел).
Копирование хранилища значений кодом на встроенном языке
Работа с хранилищем идёт на сервере: там доступен объект справочника или документа, и там же нет лишней передачи больших данных на клиент.
Простая копия внутри базы
Пример для справочника с реквизитом Файл типа ХранилищеЗначения:
&НаСервереБезКонтекста
Процедура СкопироватьХранилищеНаСервере(Источник, Приемник)
ОбъектПриемник = Приемник.ПолучитьОбъект();
ОбъектПриемник.Файл = Источник.Файл;
ОбъектПриемник.Записать();
КонецПроцедуры
Источник.Файл читается прямо через ссылку, отдельно получать объект-источник не нужно. Без вызова Записать() копия останется в памяти и пропадёт.
Копия с пересозданием и сжатием
Если исходное хранилище создавали без сжатия, при копировании его можно упаковать. Степень сжатия задаётся числом от 0 до 9:
Значение = Источник.Файл.Получить();
ОбъектПриемник.Файл = Новый ХранилищеЗначения(Значение, Новый СжатиеДанных(9));
ОбъектПриемник.Записать();
Для фото в формате JPG и архивов выигрыша почти не будет: они уже сжаты. Для XML, текстовых документов и таблиц значений разница бывает заметной.
Копия при интерактивном копировании объекта
Чтобы копия элемента всегда получала хранилище исходника, используйте обработчик ПриКопировании в модуле объекта:
Процедура ПриКопировании(ОбъектКопирования)
Файл = ОбъектКопирования.Файл;
КонецПроцедуры
После правки проверьте сценарий вручную: скопируйте элемент, запишите и откройте вложение в новом элементе.
Массовое копирование из одного реквизита в другой
Частый случай — переложить данные из старого реквизита ФайлСтарый в новый ФайлНовый у всех элементов. Каждый объект пишется в своей транзакции, чтобы сбой на одном элементе не откатил всю пачку:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Т";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НачатьТранзакцию();
Попытка
Объект = Выборка.Ссылка.ПолучитьОбъект();
Объект.ФайлНовый = Объект.ФайлСтарый;
Объект.Записать();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("КопированиеХранилищ", УровеньЖурналаРегистрации.Ошибка,
, Выборка.Ссылка, ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Объект.Записать() запускает все подписки и обработчики записи конфигурации. Если в них есть регистрация изменений для обмена или проверки, массовая запись создаст лишние сообщения обмена и может упасть на проверке заполнения. Для технической перекладки используйте Объект.ОбменДанными.Загрузка = Истина перед записью — это отключает обработчики и проверки, поэтому включайте его осознанно.
Выгрузка в файл и перенос между базами
Хранилище с файлом или картинкой
Если внутри лежат байты, их можно сохранить на диск и загрузить в другой базе. Сначала определите тип содержимого:
Значение = Источник.Файл.Получить();
Если ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
Значение.Записать("D:\Выгрузка\" + Строка(Источник.УникальныйИдентификатор()) + ".bin");
ИначеЕсли ТипЗнч(Значение) = Тип("Картинка") Тогда
Значение.ПолучитьДвоичныеДанные().Записать("D:\Выгрузка\" + Строка(Источник.УникальныйИдентификатор()) + ".img");
КонецЕсли;
Путь D:\Выгрузка\ указывается на компьютере, где выполняется код. В клиент-серверной базе это сервер 1С, и у пользователя, от которого запущена служба, должны быть права на запись в эту папку.
В базе-приёмнике обратная операция:
Данные = Новый ДвоичныеДанные("D:\Выгрузка\" + ИмяФайла);
Объект.Файл = Новый ХранилищеЗначения(Данные, Новый СжатиеДанных(9));
Объект.Записать();
Имя файла по уникальному идентификатору объекта удобно: при переносе обменом идентификаторы ссылок совпадают, и файл легко сопоставить с элементом.
Хранилище со структурой или таблицей
Структуры и таблицы значений переносят через XML. СериализаторXDTO умеет записывать ХранилищеЗначения как значение, а платформа упаковывает его содержимое в base64:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("D:\Выгрузка\Хранилище.xml");
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Источник.Файл, НазначениеТипаXML.Явное);
ЗаписьXML.Закрыть();
Чтение в другой базе — через ЧтениеXML и СериализаторXDTO.ПрочитатьXML(ЧтениеXML).
Ссылки внутри хранилища не перекодируются ни одним из способов. Если там лежит СправочникСсылка.Контрагенты, в чужой базе она найдёт элемент только при совпадении уникального идентификатора. Иначе после Получить() вы увидите «Объект не найден» с GUID в скобках. Такие хранилища перед переносом разбирайте и пересобирайте с поиском элементов по коду или ИНН.
Мини-кейс: перенос фото номенклатуры в новую базу
Торговая компания переходила на новую конфигурацию. Обмен перенёс 12 000 позиций номенклатуры, но фото в реквизите типа ХранилищеЗначения в правилах не было. Решение заняло один вечер:
- В старой базе обработка выгрузила каждое фото в файл с именем по уникальному идентификатору элемента.
- Папку скопировали на сервер новой базы.
- В новой базе обработка нашла элементы по идентификатору через
Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Имя)), проверила, что элемент существует, и записала фото. - Элементы без файла и файлы без элемента попали в отдельный список для ручного разбора.
Ссылка, полученная через ПолучитьСсылку, может указывать на несуществующий объект. Поэтому перед записью проверяйте её, например, запросом или через ПолучитьОбъект() с проверкой на Неопределено.
Копирование через файлы базы и SQL: где граница допустимого
Хранилища значений физически лежат в той же базе, что и всё остальное. В файловом варианте это 1Cv8.1CD, в клиент-серверном — таблицы СУБД.
Что можно делать на уровне файлов:
- ✅ копировать каталог файловой базы целиком, когда все пользователи вышли;
- ✅ делать резервную копию СУБД штатными средствами MS SQL Server или PostgreSQL;
- ✅ выгружать базу в
.dtчерез Конфигуратор:Администрирование → Выгрузить информационную базу.
Чего делать не стоит:
- ❌ копировать файл
1Cv8.1CDво время работы пользователей: копия может оказаться несогласованной; - ❌ переносить поле с хранилищем между таблицами SQL-запросом. Формат поля внутренний, платформа не узнает о правке, а структура таблиц меняется от релиза к релизу;
- ❌ пытаться вытащить одно хранилище из
.dt— файл выгрузки загружается только целиком.
Загрузка .dt полностью заменяет данные базы-приёмника. Для выборочного переноса хранилищ используйте код из предыдущих разделов, а не загрузку выгрузки поверх рабочей базы.
Автоматизация: обработка, регламентное задание, пакетный запуск
Разовую перекладку удобно оформить внешней обработкой: форма с выбором источника и приёмника и серверная процедура с кодом из раздела выше. Обработку открывают через Файл → Открыть в режиме «Предприятие».
Для регулярной выгрузки на диск подходят три варианта:
- Регламентное задание в доработанной конфигурации или расширении. Выполняется на сервере 1С по расписанию, удобно для ночной выгрузки вложений.
- Пакетный запуск с параметром
/Execute, который открывает обработку сразу после входа:
"C:\Program Files\1cv8\8.3.24.1548\bin\1cv8.exe" ENTERPRISE /F "D:\Bases\Torg" /N "Робот" /P "пароль" /Execute "D:\Обработки\ВыгрузкаХранилищ.epf"
Номер платформы в пути подставьте свой. Обработка должна сама завершать сеанс после работы, иначе окно останется висеть.
- Внешнее соединение из скрипта или другой базы 1С: подходит, когда копирование — часть большего сценария обмена.
Для пакетного запуска заведите отдельного пользователя с правами только на нужные объекты. Пароль в bat-файле лежит открытым текстом, поэтому доступ к файлу ограничьте.
Если хранилищ тысячи, обрабатывайте их порциями, например по 500 элементов, и пишите прогресс в журнал регистрации. Так при обрыве задание можно продолжить с места остановки.
Проверка копии: размер, хеш, открытие
Запись без ошибки ещё не значит, что внутри то же самое. Проверка в три шага:
- Тип значения.
ТипЗнч(Приемник.Файл.Получить())совпадает с типом исходника. - Размер. Для двоичных данных сравните
Размер()у источника и приёмника. - Контрольная сумма. Посчитайте хеш содержимого:
Функция ХешДанных(Данные)
Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256);
Хеширование.Добавить(Данные);
Возврат ПолучитьHexСтрокуИзДвоичныхДанных(Хеширование.ХешСумма);
КонецФункции
Сравнивайте хеш содержимого (ДвоичныеДанные), а не самого хранилища. При другой степени сжатия упакованные байты разные, а данные внутри одинаковые.
Для структур и таблиц проверьте выборочно: количество строк, значения ключевых полей, открываются ли ссылки. Если Получить() вызывает исключение, хранилище повреждено. Причина обычно в прерванной записи или в повреждении самой базы — тогда начните с тестирования и исправления в Конфигураторе на копии базы.
Резервное копирование данных из хранилищ
Отдельной «резервной копии хранилищ значений» в платформе нет: они входят в обычную копию базы . Поэтому правила общие.
- 🗓️ Ежедневная копия СУБД или каталога файловой базы, раз в неделю дополнительно
.dt. - 📦 Перед массовой перекладкой — внеочередная копия. Обработки массового копирования пишут сразу тысячи объектов, откатить их без копии нечем.
- 🧪 Проверка восстановления: раз в месяц разверните копию в тестовую базу и откройте несколько вложений.
Хранилища с файлами быстро раздувают базу: каталог номенклатуры с фото может весить десятки гигабайт. Если копии стали долгими, выгрузите файлы на диск и храните в базе только путь, или перенесите их в присоединённые файлы с хранением в томах, если конфигурация на БСП это поддерживает. База станет легче, а файлы получат свою схему копирования.
Можно ли просмотреть содержимое хранилища значений без кода?
Получить() или готовая обработка, которая выводит значение на форму.Почему после копирования хранилище пустое?
Записать().