Организация хранения файлов в базе данных Microsoft SQL Server. Универсальный способ

Современные базы данных могут хранить самые различные виды информации. В том числе, целые файлы.

Обычно хранения файлов непосредственно в базе данных стараются избегать, так как это приводит к усложнению процесса разработки, как самой базы данных, так и клиентского приложения. А, также к увеличению размера базы данных. Однако в целом ряде случаев именно такой подход  становится наилучшим решением.

Современные системы управления, базами данных, включая Microsoft SQL Server (MS SQL), и средства программирования прекрасно справляются с данной задачей.

Существуют два способа хранения файлов в базах данных MS SQL.

  • Хранение файла в поле с двоичными данными (тип данных VARBINARY(MAX));
  • Использование файловых таблиц.

Второй способ стал доступен вместе с появлением файловых таблиц в MS SQL 2012 и в более ранних версиях его использование не возможно. Первый способ поддерживают все без исключения версии MS SQL (включая 2014) и он является, по сути, универсальным. Именно он и будет рассмотрен в данной статье.

Суть этого способа предельно проста. Создаётся поле с типом данных VARBINARY(MAX) (именно этот тип данных может сохранять в себе файлы, в том числе, весьма внушительных размеров) и в него из клиентской программы загружаются файлы в виде двоичных данных.

Так как файлы могут иметь значительный размер лучше для их хранения создать отельную таблицу. Для удобства можно добавить в эту таблицу поле с именем файла или его расширением. Дело в том, что в поле с двоичными данными сохраняется только содержимое файла. Поэтому информация о его имени и расширении может оказаться весьма полезной в последующей работе. Особенно при выгрузке файла из базы данных обратно на диск.

Вот примерный вариант такой таблицы:

  • id – уникальный идентификатор. Первичный ключ;
  • fileName – строковое поле (например, nvarchar(255)) с именем файла;
  • binaryData – поле с двоичными данными (VARBINARY(MAX)) в котором собственно и хранится файл.

Рассмотрим работу с такой таблицей из программы клиента на примере Delphi и C#.

Загрузка и выгрузка файлов в Delphi

При загрузке вначале необходимо составить запрос на добавление.

После этого нужно присвоить значения параметрам этого запроса.

Так как многие компоненты для работы с базами данных, включая стандартный набор для ADO, умеют загружать двоичные данные напрямую из источника в виде файла или потока, никаких манипуляций с blob и файловыми потоками при загрузке не требуется. Содержимое файла будет прочитано при присвоении значения параметра.

Далее остаётся только выполнить составленный запрос, и файл будет загружен в таблицу базы данных.

Выгрузка на диск осуществляется сложнее.

Сначала необходимо получить выборку, содержащую двоичные данные файла и его название.

Далее создаём пустой файл, в который будет записано содержимое из базы данных.

После этого создаём blob поток для получения двоичных данных из базы.

Переменная blob имеет тип TStream.

Теперь можно создавать файловый поток и с его помощью поместить данные из blob потока в созданный ранее файл.

Переменная fs имеет тип TFileStream.

По завершении, освобождаем ресурсы, уничтожая оба потока.

Загрузка и выгрузка файлов в C#

Загрузка и выгрузка файлов в .NET Framework имеет тот же принцип, что и в Delphi. Отличие только в том, что для реализации используются другие средства.

При загрузке необходимо прочитать файл в массив байтов.

Далее следует подключиться к базе данных, создать запрос на добавление, присвоить значения параметров и выполнить запрос.

При выгрузке вначале получаем выборку с названием файла и его содержимым

Далее читаем содержимое файла из базы в массив байт.

После этого остаётся только записать байты из массива в файл, используя его имя, сохранённое в базе данных.

Работа с файлами большого размера

Если файл имеет достаточно большой размер, то для его загрузки или выгрузки потребуется значительное время. Особенно на ЭВМ, не обладающих высокой мощностью.

Со стороны это выглядит так, что программа как будто «зависла». На самом же деле она просто обрабатывает операцию по загрузке или выгрузке крупного файла.

Чтобы этого избежать следует выполнять данные операции в отдельном потоке.

2 комментария

  1. AssignFile(f,fileName); Rewrite(f); CloseFile(f); можно заменить fs:=TFileStream.Create(fileName,fmCreate or fmOpenWrite); fs.CopyFrom(blob,blob.Size); код будет короче и проще для восприятия.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *