Загрузка рисунков в БД

Константин аватар

В процессе работы, достаточно часто возникает ситуация, когда работать приходится не только со стандартными типами данных в базе, но и с изображениями, звуками и другими неструктурированными объектами. При этом можно выделить два основных подхода к хранению подобной информации: 1. В БД хранится только путь к файлу, сам файл хранится на жестком диске. 2. Весь объект хранится в БД в сециальном поле с типом blob
В ряде серверов БД, например Micro$oft SQL 2008 появилась возможность объединить эти подходы, отчасти устранив ряд недостатков первого и второго. Но как обычно у гибридов, решив несколько старых проблем, приобретаем несколько новых. Впрочем речь не об этом.
В этой статье я хотел бы еще раз рассмотреть тему сохранения и извлечения неструктурированной информации на примере сервера БД Firebird и Borland Builder C++ 6. Что бы не усложнять материал, я буду рассматривать работу с рисунками (точнее фотографиями) в формате bmp и jpeg. И затем расскажу как можно расширить приведенную схему.
Итак для работы на нужно создать таблицу, которая содержит идентификатор и связанное с ним изображение. Делает это следующий скрипт:

CREATE TABLE PEOPLE_PHOTOS (
    PEOPLE_ID     INTEGER NOT NULL,
    PEOPLE_PHOTO  BLOB SUB_TYPE 0 SEGMENT SIZE 80 NOT NULL
);

Для операции вставки (модификации) служит хранимая процедура:

CREATE OR ALTER PROCEDURE PEOPLE_PHOTO_INS (
    people_id integer,
    people_photo blob sub_type 0 segment size 80)
as
declare variable tmp_count integer = 0;
begin
  /* Procedure Text */
  select count(*) from people_photos where people_id = :people_id into :tmp_count;
  if (:tmp_count = 1) then
   begin
     update people_photos set
     people_photo = :people_photo where people_id = :people_id;
   end
  else if (:tmp_count = 0) then
   begin 
    insert into people_photos (people_id, people_photo) values (:people_id, :people_photo);
   end
  

  suspend;
end 

Для выборки

CREATE OR ALTER PROCEDURE PEOPLE_PHOTO_SEL (
    people_id integer)
returns (
    people_photo blob sub_type 0 segment size 80)
as
begin
  /* Procedure Text */
  select people_photo from people_photos where people_id = :people_id into :people_photo;
  suspend;
end

Добавлению изображения в базу на стороне клиента служит следующий код:

//Заносим в параметр идентификатор 
 dmMain->fibPhotoIns->ParamByName("people_id")->Value = PeopleId;
 TMemoryStream *pMS = new TMemoryStream;
 Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap;
 TJPEGImage *tmpImg = new TJPEGImage();
 try{
//Загружаем изображение из файла и сохраняем его в поток
//если это JPEG 
    tmpImg->LoadFromFile(opOpen->FileName);
   tmpImg->SaveToStream(pMS);

 }catch(...){
//если нет - то обрабатываем исключение и загружаем битмеп
  tmpBitmap->LoadFromFile(opOpen->FileName);
  tmpBitmap->SaveToStream(pMS);

 }
//Загружаем из потока в параметр и вызываем процедуру
 dmMain->fibPhotoIns->ParamByName("people_photo")->LoadFromStream(pMS);
 dmMain->fibPhotoIns->ExecProc();
 delete pMS;
 delete tmpBitmap;
 delete tmpImg;

Соотвественно получение изображения из базы в компонент TImage

  imPhoto->Picture->Bitmap->CleanupInstance();
  dmMain->fibPhoto->ParamByName("people_id")->Value = tmp;
  dmMain->fibPhoto->Active = true;
  TMemoryStream *pMS = (TMemoryStream*)dmMain->fibPhoto->CreateBlobStream(dmMain->fibPhoto->FieldByName("people_photo"),bmRead);
  if(!pMS->Size){
   dmMain->fibPhoto->Active = false;
   return;
  }
  TJPEGImage *tmpImage = new TJPEGImage();
  Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap;

 try{
 pMS->Position = 0;
 tmpImage->LoadFromStream(pMS);
 imPhoto->Picture->Bitmap->Assign(tmpImage);

 }
 catch(...){
 pMS->Position = 0;
 tmpBitmap->LoadFromStream(pMS);
 imPhoto->Picture->Bitmap->Assign(tmpBitmap);

  }
 delete pMS;
 delete tmpImage;
 delete tmpBitmap;
 dmMain->fibPhoto->Active = false;

Обращаю ваше внимание - не забывайте устанавливать позицию потока в 0. Если вы получаете ошибку "JPEG error #52" - значит либо вы забыли это сделать, либо ваш файл не JPEG.
Если в работе вам надо использовать более чем два типа файлов, то генерация исключений будет достаточно накладным решением. В таком случае нужно дополнительно вводить поле типа файла и обрабатывать его, оставляя исключения только для ошибок, либо же пытаться распознавать тип файла по сигнатуре.

Обсудить статью на форуме

Комментарии

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".
Константин аватар

Re: Загрузка рисунков в БД

Таисия написал:
А что такое БД?
И с чем его едят?

БД - база данных.

============================================

Во имя Отца и Сына и Святаго Духа

Re: Загрузка рисунков в БД

А что такое БД?
И с чем его едят?

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".