На текущий момент в конфигурациях 1С наиболее распространены два способа хранения прикрепленных файлов:
- Непосредственно в базе 1С
- В файловом хранилище.
О достоинствах и недостатках этих способов рассказано весьма подробно.
Существует и третий способ - хранение файлов во внешней базе, к примеру, MS SQL Server. До версии MS SQL Server 2008 данный способ не особо отличался от первого способа, т.е. хранения непосредственно в базе данных. Но начиная с MS SQL Server 2008 разработчикам была предложена новая технология хранения неструктурированных данных FileStream.
Если вкратце - технология FileStream предоставляет особый способ хранения и доступа к файлам:
- На уровне СУБД файл помещается в определенное поле таблицы, но хранится при этом в особой файловой группе.
- Каждой записи соответсвует физический файл на диске.
- Доступ к файлам обеспечивает MS SQL Server, т.е. поддерживается транзакционное чтение/запись и ограничение доступа на основе прав доступа пользователя СУБД, а не Windows.
- Файлы хранятся в специальной файловой группе, поэтому возможно расположение их на отдельном физическом диске.
- Файловую группу FileStream возможно включать в бэкап базы.
- Доступ к файлам возможен как через T-SQL-запросы, так и посредством потокового доступа (API файловой системы win32).
- При потоковом доступе не используется память MS SQL Server, отсутствует высокая нагрузка на сервер, для кэширования файлов используется системный кэш Windows.
Приятным дополнением является полноценная поддержка FileStream бесплатным SQL Express, при этом отсутствуют какие-либо ограничения на размер файловой группы FileStream.
Существуют и ряд недостатков технологии FileStream:
- На диске все файлы размещаются в одном каталоге, что при большом количестве файлов приводит к проблемам со скоростью доступа. Microsoft дает несколько рекомендаций при использовании томов хранилища FileStream.
- С мелкими файлами (менее 1 Мб), особенно при потоковом доступе, обеспечивается более низкая скорость доступа, чем при хранении файлов напрямую в базе. Сравнение производительности различных технологий доступа к файлам
- Для реализации потокового доступа к файлам требуется написание специального клиентского приложения, в случае 1С - создание внешней компоненты.
Как правило, прикрепляемые файлы в 1С имеют различный размер и утверждать, что большинство будут иметь размер больше 1 Мб или наоборот, было бы ошибочно. Поэтому было решено создать базу MS SQL, которая хранит файлы, как непосредственно в базе, так и в файловой группе FileStream.
База MS SQL состоит из трех таблиц:
1) innerStorage для хранения файлов непосредственно в базе,
2) outerStorage для внешнего хранения файлов FileStream,
3) locationStorage - для определения в какой таблице хранится файл.
Скрипт для создания базы со всеми таблицами и хранимыми процедурами приложен в архиве.
В качестве идентификатора файла выступает ГУИД, в MS SQL он преобразуется в тип uniqueidentifier. Для передачи параметра между системами используется преобразование к строке.
В базе 1С указывается пограничный размер файла: если помещаемый файл меньше указанного размера, то файл помещается в таблицу innerStorage, больше - outerStorage. Одновременно делается запись в таблицу locationStorage о расположении файла.
При получении файла в 1С, сначала делается запрос о расположении файла, а затем запрос к соответствующей таблице.
При обновлении файла также сначала делается запрос о расположении файла, вычисляется размер для определения нового типа расположения. Если тип расположения меняется, то старый файл удаляется из старого места и добавляется в новое.
Запись файлов непосредственно в базу данных довольно тривиальная задача. Описаний решений существует великое множество, к примеру, //infostart.ru/public/283336/ Описанные методы кодирования/декодирования из двоичных данных в Base64 успешно работают. Для небольших файлов скорость работы вполне удовлетворительная.
Из особенностей моей реализации данной подсистемы можно отметить:
- Использование хранимых процедур и функций для добавления, обновления, удаления и получения файлов.
- Использование механизма внешних источников данных у 1С для вызова хранимых процедур.
В принципе, можно было все реализовать более традиционным способом через создание ADO соединения, но подход, когда база предоставляет все необходимое АПИ для работы является более правильным. Использование внешних источников 1С позволило сделать код 1С еще минимальней:
//добавление файла
ПараметрыСоединения = Новый ПараметрыСоединенияВнешнегоИсточникаДанных;
ПараметрыСоединения.СтрокаСоединения = "DRIVER={SQL Server};" + СтрокаПодключения;
ХранилищеВнешнихФайлов = ВнешниеИсточникиДанных.ХранилищеВнешнихФайлов;
ХранилищеВнешнихФайлов.УстановитьОбщиеПараметрыСоединения(ПараметрыСоединения);
ХранилищеВнешнихФайлов.УстановитьСоединение();
ХранилищеВнешнихФайлов.ДобавитьФайл(ИдФайла, Base64Строка(ДанныеФайла));
С организацией хранения больших файлов с использованием технологии FileStream все оказалось несколько сложней. Непосредственно создание базы и таблицы для хранения файлов не вызывает никаких вопросов. Все подробно описано. Непосредственно доступ к файлам возможен, как через Transact-SQL-запросы, так и использование API файловой системы.
В случае Transact-SQL-запросов решение было бы практически идентично первому способу - изменения только на внутреннем уровне хранения файлов. При этом на MS SQL Server легла бы высокая и не свойственная ему нагрузка по извлечению, кодированию/декодированию больших файлов.
Для потокового доступа к файлам на уровне клиентских приложений существует dotNet класс SqlFileStream. Примеры его использования на различных языках присутствуют в избытке.
Только одна проблема - 1С не умеет работать напрямую с dotNet классами. Поэтому пришлось реализовать COM-объект для работы с классом SqlFileStream из 1С. В архив приложены 32-х разрядная версия внешней компоненты SqlStreamAccess.dll и 64-х разрядная SqlStreamAccess64.dll. Регистрация Com-объекта производится путем вызова regasm.exe нужной разрядности под полными правами.
Реализованный COM-объект имеет одно свойство ConnString и два метода: InsertFile и SelectFile, которые позволяют добавлять, обновлять и получать файлы.
Пример работы с COM-объектом SqlStreamAccess:
// добавление нового файла
ТипДобавления = 1; //создание новой записи
ФайлПоток = Новый COMОбъект("SqlStreamAccess.SqlFile");
ФайлПоток.ConnString = СтрокаПодключения;
ФайлПоток.InsertFile(ИдФайла, ИмяФайла, ТипДобавления);
ФайлПоток = Неопределено;
// получение файла
ФайлПоток = Новый COMОбъект("SqlStreamAccess.SqlFile");
ФайлПоток.ConnString = СтрокаПодключения;
ФайлПоток.SelectFile(ИдФайла, ИмяФайла);
ФайлПоток = Неопределено;
В качестве идентификатора файла также выступает ГУИД, приведенный к строке. В качестве имени файла указывается полный путь к файлу, который должен быть помещен/получен из базы. Естественно, пользователь Windows, под которым запущен сервис 1С, должен иметь полный доступ к этому файлу. Также данный пользователь должен иметь права для доступа к базе MS SQL посредством Windows-аутентификации.
Отдельного объяснения требует третий параметр метода "InsertFile". Он имеет целочисленый тип данных и может принимать три значения:
1 - проиcходит добавление файла
2 - происходит обновление файла без смены типа хранилища
3 - происходит обновление файла со сменой типа хранилища (удаляется из innerStorage, добавляет в OuterStorage).
Примеры работы с внешним хранилищем файлов можно посмотреть в приложенной в архиве конфигурации 1С. Встроенная обработка "РаботаСВнешнимХранилищемФайлов" предоставляет все высокоуровненые методы для получения, добавления, обновления и удаления файлов.