Часто возникает необходимость хранить присоединенные файлы где-нибудь на сетевом диске, чтобы как-то сократить рост размера базы.
К большому сожалению, приходится изобретать велосипед, т.к. в УПП 1.3 (заметьте, версия продается и поддерживается) НЕТ! хранения файлов вне базы.
Да, эта возможность уже реализована в УПП 1.3 для электронных документов, а все остальное по-прежнему хранится в базе.
"Допилок" этой функциональности много, есть и платные. Предлагаю свой варинат велосипеда. Версия рабочая, проверялась на УПП 1.3.72.3.
Побежали!
Включим хранение файлов в томах на диске
Добавим в справочник "ХранилищеДополнительнойИнформации" два реквизита:
ИмяФайлаВТоме (тип "Строка(50)")
НомерВерсии (тип "Число(10)")
В модуле объекта справочника "ХранилищеДополнительнойИнформации" пишем код (реквизит "Хранилище" очистим, а данные сохраним на диск). Использована типовая процедура "ФайловыеФункции.ДобавитьНаДиск", которая позволит также контролировать размер файла и запишет в имя файла на диске версию:
Процедура ПередЗаписью(Отказ)
//+wowik
Если ФайловыеФункции.ПолучитьТипХраненияФайлов() <> Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
Если Хранилище.Получить() <> Неопределено Тогда // когда помечается элемент на удаление, то хранилище пустое
Если не ЗначениеЗаполнено(ИмяФайлаВТоме) Тогда
ИмяФайлаВТоме = Строка(Новый УникальныйИдентификатор);
НомерВерсии = 1;
Иначе
НомерВерсии = НомерВерсии + 1; //будем сохранять версии файлов на всякий случай
КонецЕсли;
Если Этотобъект.ВидДанных = Перечисления.ВидыДополнительнойИнформацииОбъектов.Файл Тогда
РасширениеФайла = СтрЗаменить(Прав(ИмяФайла,4),".","");
ДвоичныеДанныеФайла = Хранилище.Получить();
Иначе
РасширениеФайла = "bmp";
ВременныйФайл = ПолучитьИмяВременногоФайла(РасширениеФайла);
Картинка = Хранилище.Получить();
Картинка.Записать(ВременныйФайл);
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ВременныйФайл);
КонецЕсли;
ПутьКФайлуВТоме = ИмяФайлаВТоме+"."+РасширениеФайла;
РазмерФайла = ДвоичныеДанныеФайла.Размер();
ФайловыеФункции.ДобавитьНаДиск(
ДвоичныеДанныеФайла,
ПутьКФайлуВТоме,
"", //ссылка на том, все равно она обнуляется в процедуре ДобавитьНаДиск
1,
НомерВерсии,
ИмяФайлаВТоме,
РасширениеФайла,
РазмерФайла,
Ложь,
ТекущаяДата()
);
//хранилище элемента очищаем
Хранилище = Неопределено;
КонецЕсли;
КонецЕсли;
//-wowik
КонецПроцедуры
Далее в каком-либо общем модуле (в моем случае общий модуль "wowikОбщийМодуль") добавляем функцию:
Функция ПолучитьДвоичныеДанныеФайлаВХранилище(ХранилищеДополнительнойИнформацииСсылка, ВернутьХранилищеЗначения = Ложь) Экспорт
Если ФайловыеФункции.ПолучитьТипХраненияФайлов() = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
Если ВернутьХранилищеЗначения Тогда
Возврат ХранилищеДополнительнойИнформацииСсылка.Хранилище;
Иначе
Возврат ХранилищеДополнительнойИнформацииСсылка.Хранилище.Получить();
КонецЕсли;
Иначе
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТомаХраненияФайлов.Ссылка
|ИЗ
| Справочник.ТомаХраненияФайлов КАК ТомаХраненияФайлов
|ГДЕ
| ТомаХраненияФайлов.ПометкаУдаления = &ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| ТомаХраненияФайлов.ПорядокЗаполнения";
Запрос.УстановитьПараметр("ПометкаУдаления", Ложь);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() = 0 Тогда
ВызватьИсключение(НСтр("ru = 'Нет ни одного тома для размещения файла.'"));
КонецЕсли;
Пока Выборка.Следующий() Цикл
СсылкаНаТом = Выборка.Ссылка;
ПутьКТому = ФайловыеФункции.ПолныйПутьТома(СсылкаНаТом);
ИмяФайлаВТоме = ХранилищеДополнительнойИнформацииСсылка.ИмяФайлаВТоме;
Если ЗначениеЗаполнено(ИмяФайлаВТоме) Тогда
НайденныеФайлы = НайтиФайлы(ПутьКТому,"*"+ИмяФайлаВТоме+"*",Истина);
Если НайденныеФайлы.Количество() > 0 Тогда
//получить последнюю версию файла. Предполагается что файлы беспорядочно отсортированы
ПолучитьФайлСНомером = 1;
ИндексНайденногоФайла = 0;
Для Каждого НайденныйФайл из НайденныеФайлы Цикл
НомерВерсии = Число(СтрЗаменить(Прав(НайденныйФайл.ИмяБезРасширения,2),".",""));
Если НомерВерсии >= ПолучитьФайлСНомером Тогда
ПолучитьФайлСНомером = НомерВерсии;
ФайлВТоме = НайденныйФайл;
КонецЕсли;
КонецЦикла;
ПутьКФайлуЛокальный = ПолучитьИмяВременногоФайла(ФайлВТоме.Расширение);
КопироватьФайл(ФайлВТоме.ПолноеИмя, ПутьКФайлуЛокальный); //открыть картинку из локального диска быстрее получится, чем по сети открыть
Если ВернутьХранилищеЗначения Тогда
Возврат Новый ХранилищеЗначения(Новый ДвоичныеДанные(ПутьКФайлуЛокальный));
Иначе
Возврат Новый Картинка(ПутьКФайлуЛокальный);
КонецЕсли;
КонецЕсли;
Иначе
Если ВернутьХранилищеЗначения Тогда
Возврат Новый ХранилищеЗначения(Неопределено);
Иначе
Возврат Новый Картинка;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецФункции
Далее ищем глобальным поиском выражение "Хранилище.Получить()":
в большинстве случаев замена проста:
...
//мТекущееОсновноеИзображение = ОсновноеИзображение.Хранилище.Получить(); //wowik
мТекущееОсновноеИзображение = wowikОбщийМодуль.ПолучитьДвоичныеДанныеФайлаВХранилище(ОсновноеИзображение); //wowik
...
//ЭлементКартинки.Картинка = ОсновноеИзображение.Хранилище.Получить(); //wowik
ЭлементКартинки.Картинка = wowikОбщийМодуль.ПолучитьДвоичныеДанныеФайлаВХранилище(ОсновноеИзображение); //wowik
...
Но в некоторых случаях сложнее, например в процедуре "ОтображениеИзображения()" формы "ФормаИзображения" справочника "ХранилищеДополнительнойИнформации":
Процедура ОтображениеИзображения()
//+wowik
Если Хранилище.Получить() = Неопределено Тогда
Если ФайловыеФункции.ПолучитьТипХраненияФайлов() = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
ЭлементыФормы.ПолеИзображения.Картинка = Новый Картинка();
Иначе
Если НЕ ЗначениеЗаполнено(ИмяФайлаВТоме) Тогда
ЭлементыФормы.ПолеИзображения.Картинка = Новый Картинка();
Иначе
КартинкаВТоме = wowikОбщийМодуль.ПолучитьДвоичныеДанныеФайлаВХранилище(Ссылка);
ЭлементыФормы.ПолеИзображения.Картинка = КартинкаВТоме;
Хранилище = Новый ХранилищеЗначения(КартинкаВТоме);
КонецЕсли;
КонецЕсли;
Возврат;
КонецЕсли;
Если ВидДанных = Перечисления.ВидыДополнительнойИнформацииОбъектов.Изображение Тогда
ЭлементыФормы.ПолеИзображения.Картинка = Хранилище.Получить();
Иначе
ЭлементыФормы.ПолеИзображения.Картинка = Новый Картинка();
КонецЕсли;
//-wowik
КонецПроцедуры
Отображение картинок поправили, теперь переходим к сохранению и открытию внешних файлов:
в общем модуле "РаботаСФайлами" исправляем:
...
//СохранитьФайл(СтруктураПараметров, СсылкаФайл.ИмяФайла, СсылкаФайл.Хранилище, СпособПерезаписи); //wowik
СохранитьФайл(СтруктураПараметров, СсылкаФайл.ИмяФайла, wowikОбщийМодуль.ПолучитьДвоичныеДанныеФайлаВХранилище(СсылкаФайл,Истина), СпособПерезаписи); //wowik
...
//ДанныеФайла = СсылкаФайл.Хранилище; //wowik
ДанныеФайла = wowikОбщийМодуль.ПолучитьДвоичныеДанныеФайлаВХранилище(СсылкаФайл,Истина);//wowik
...
в общем модуле "ФайловыеФункции" ставим "попытку":
Попытка //wowik
// Установим время изменения файла таким, как оно стоит в текущей версии
ФайлНаДиске = Новый Файл(ПолноеИмяФайлаСПутем);
ФайлНаДиске.УстановитьВремяИзменения(ВремяИзменения);
ФайлНаДиске.УстановитьТолькоЧтение(Истина);
Исключение
КонецПопытки;
Возможно, еще где-то придется что-то закомментировать. Далее все решается отладкой уже в конфигурации.
И все. Спасибо. Удачного внедрения!