# Native Code > برنامه نویسی در Delphi > بانک های اطلاعاتی در Delphi >  ذخیره فایل  Jpg در دیتابیس ؟

## mojtaba_z

سلام
چطوری میشه یه تصویر Jpg را در یه دیتابیس از نوع Access یا Sql Server ذخیره کرد.
(من از AdoQuery استفاده میکنم) لطفا یه مثال بزنید.
ممنون.

----------


## SReza1

این کار رو نمیشه کرد!! فقط میتونی از memorystream استفاده کنی و فایل jpg را در ان ذخیرخه کنی و اونو در db نگهداری کنی

----------


## Kambiz

به فرض که یک ADOQuery با یک فیلد از نوع Blob یا Memo به نام BlobField داشته باشیم و بخواهیم تصویر موجود در یک TImage رو در این فیلد ذخیره کنیم (فرض بر این هست که Query در حالت Insert یا Edit قرار داره):

procedure TForm1.btnSaveImageClick&#40;Sender&#58; TObject&#41;;
var
  Stream&#58; TStream;
begin
  Stream &#58;= ADOQuery1.CreateBlobStream&#40;ADOQuery1BlobField, bmWrite&#41;;
  try
    Image1.Picture.Graphic.SaveToStream&#40;Stream&#41  ;;
  finally
    Stream.Free;
  end;
end;
و برای خواندن از فیلد و قراردادن تصویر در TImage:

procedure TForm1.btnLoadImageClick&#40;Sender&#58; TObject&#41;;
var
  Stream&#58; TStream;
begin
  Stream &#58;= ADOQuery1.CreateBlobStream&#40;ADOQuery1BlobField, bmRead&#41;;
  try
    Image1.Picture.Graphic.LoadFromStream&#40;Stream&#  41;;
  finally
    Stream.Free;
  end;
end;

در هر دو حالت فرض بر این هست که ویژگی Graphic مقدار دهی اولیه شده و nil نیست.

----------


## mojtaba_z

سلام به همگی
من وقتی از  TStream  استفاده میکنم فایل های JPG به BMP تبدیل میشن و بعد در دیتابیس
ذخیره میشن.
مشکل من اینه که تعداد زیادی تصویر JPG  دارم و اگه بصورت BMP  در دیتابیس ذخیره بشن
حجم دیتابیس خیلی خیلی زیاد زیاد بالا میره . برای این میخام با همان حجم کم بصورت  JPG
ذخیره کنم .
 بازم ممنوم .

----------


## shaniaki

با عرض ادب:

در آنصورت باید خود فایل را به صورت Stream در یک Blob ذخیره کنی( بدون بارگذاری آن در یک Image و استفاده از توابع های کلاس های Picture و Graphics)

یه عشق برنامه نویسی خفن

----------


## parniant

با سلام 
ما تو برنامه نویسی از دلفی با بانک sql استفاده می کنیم با توجه به مطالب بالا ما نتونستیم در اس کیو ال نوع blob را پیدا کنیم؟از نوع image استفاده کردیم امادر خط زیر از ADOQuery1BlobField اشکال می گیره
Stream := ADOQuery1.CreateBlobStream(ADOQuery1BlobField, bmWrite);
با اینکه یک جدول با نام blob ساختیم و یه فیلد با نام blobfield از نوع image داریم ما می خواهیم عمل ذخیره و بازیابی عکس رو تو دلفی با بانک اس کیو ال انجام بدیم اگه می شه کمک کنید 
ضمنا برای استفاده از قطعه کدهای بالا (که شامل stream , blob) هستند باید نام تابع خاصی رو توی var بنویسیم یا نه؟
می شه در مورد blob ,stream هم توضیح بدین ممنون می شم ؟

----------


## shervin farzin

سلام
نوع Image در sql همون مقدار BLOB  رو ذخيره ميكنه .
در مورد ذخيره و بازيابي عكس در SQL قبلا تو همين سايت بحث شده . به
لينك زير مراجعه كنيد:
https://barnamenevis.org/showthread.php?t=124596
اما در مورد سوال شما بايد دو نكته رو خدمت شما بگم .
اول اين كه كدي كه براي ذخيره كردن Stream نوشتين اشتباه و بايد به صورت زير
اصلاحش كنيد :
stream:=ADOQuery1.CreateBlobStream(ADOQuery1.Field  ByName('BlobField'),bmRead);
در ضمن در قسمت Var فقط كافيه Stream رو از نوع Tstream تعريف كنيد .
نكته دوم اينه كه بين ذخيره كردن عكس BMP با عكس JPG فرق هست . فرقش هم
در اينه كه زمان بازيابي اونها اگر پسوند عكس BMP باشه با روشي كه دوستم در پست
شماره 3 ارائه كرده قابل اجراء است ولي اگه پسوند عكس JPG باشه بايد از روش ديگه اي
كه در لينك بالا ملاحظه خواهيد كرد استفاده كنين .
موفق باشيد .

----------


## parniant

با تشکر از شما فرزین عزیز می شه کدی به همین صورت برای بازیابی عکس هم بذارین راستشو بخواین خسته شدم بس که جستجو کردم

----------


## m-khorsandi

ذخیره کل یک فایل در یک فیلد بانک اطلاعاتی
ذخیره عکس در sql server2000

----------


## parniant

با سلام همانطور که در پست های بالا گفته شده بود که adoquery باید در حالت edit یا insertقرار داشته باشه می خواستم ببینم چطور می تونم adoquery رو در این حالت قرار بدم ؟ و اینکه در هنگام ذخیره و بازیابی edit یا insert  باشه فرق می کنه یا نه ؟ (چون با اجرای اون قطعه برنامه بالا پیغام می ده که adoqueryنیست در حالت editیا insert )
با تشکر

----------


## shervin farzin

سلام
فرض كنيد كه جدولي داريم با نام picsample كه توي اين جدول يك فيلد از نوع Image با نام
pic ساختم و عكسم رو هم داخلش ذخيره كردم . براي بازيابي اون عكس از كد زير استفاده
ميكنم :
var
  pic:TJPEGImage;
  stream:Tstream;
begin
With ADOQuery1 do
  begin
    sql.text:='select * from picsample';
    Open;
  end;
stream:=ADOQuery1.CreateBlobStream(ADOQuery1.Field  ByName('pic'),bmRead);
if stream.Size<>0 then
  begin
    if copy(ADOQuery1.FieldByName('pic').AsString,1,1)='B  ' then
      image1.Picture.Bitmap.LoadFromStream(x)
    else
      begin
        pic:=TJPEGImage.Create;
        pic.LoadFromStream(x);
        image1.Picture.Assign(pic);
        pic.Free;
      end;
  end
else image1.Picture.Graphic:=nil;
stream.Free;

به يه نكته هم توجه كنيد كه در خط شماره 13 كه با IF كاراكتر اول Stream ذخيره شده در فيلد
pic رو با كاراكتر B مقايسه كردم علت اين بوده كه متوجه شدم اگه فايل عكس با پسوند BMP 
باشه اون كاركتر اول مقدارش B ميشه ( در واقع سه كاركتر اول BMP ميشه ) . براي همين تو
اون خط تست ميكنم كه اگه عكس BMP بود از روش Load مخصوص خودش استفاده كنم .
100 البته كه اين يه روش من درآوردي و شايد روش بهتر و بهينه تري هم بتونين براش پيدا كنين .
يه نكته ديگه هم اين كه فراموش نكنيد كه كلاس JPEG رو در ابتداي Unit در بخش Uses اضافه
كنيد . در ضمن با اجراء اون Select  كه اول همين كد نوشتم ADOQuery در حالت مورد نياز 
قرار ميگيره و كار ديگه اي لازم نداره .
اگه با كد بالا مشكلي نداشتين و بعدا خواستين در مورد حالتي كه كاربر برنامتون براي فيلد
عكس هيچ مقداري در نظر نگيره اطلاعات داشته باشيد به لينك زير يه نگاهي بندازين
https://barnamenevis.org/showthread.php?t=124721
تو اين لينك كد وارد كردن عكس به DataBase هم هست .
موفق باشيد .

----------


## parniant

با سلام به شما کامبیز عزیز و تمام دوستان 
من هم همونطوری که شما گفتید عمل کردم اما می خوام ببینم برای بازیابی یک عکس ذخیره شده که برای هر کد یک عکس وارد می کنم (برای صدور کارت افراد ) در کدوم قسمت باید بگم با توجه به شماره کد افراد عکس اون فرد رو نشون بده (می تونید در یک مثال کامل برام بذارید که جدول شامل چهار فیلد کد و نام و نام خانوادگی و عکس هر فرد باشه و بتونم عمل ثبت افراد با عکسشون و و بازیابی عکس هر فرد با توجه به کد او و ویرایش عکس هر فرد با توجه به کد او رو انجام بده ) از دلفی با بانک sql استفاده می کنم ممنون می شم کمک کنید خیلی دنبال گشتم اما چیز درست حسابی پیدا نکردم اگه شما می دونید در تاپیک خاصی هست اگه می شه آدرس اونو برام بذارید ممنون می شم البته اگه به مطلب می خوره

----------


## shervin farzin

سلام
يه برنامه با مشخصاتي كه گفته بوديد رو نوشتم و براتون گذاشتمش ، چند نكته هم در مورد
برنامه بايد اضافه كنم .
1- اين برنامه رو با Delphi 2007 نوشتم .
2- قبل از استفاده كردن ازش حتما محتواي Connection String در كامپوننت AdoQuery رو 
    مطابق با نام Database خودتون تنظيم كنيد .
3- Personel نام جدول مورد استفاده تو اين برنامست كه چهار فيلد داره
    Id كه يه مقدار AutoNumber در جدول تعريف شده .
    F_name كه نام پرسنل رو داره
    L_name كه نام خانوادگي پرسنل رو داره
    Pic كه عكس پرسنل رو نگه ميداره .
4- به رويداد OnCellClick از DBGrid و توابع اعلان شده در بخش Public فرم توجه كنيد .
5- داخل برنامه ، با راست كليك كردن روي Grid عمليات ورود ، ويرايش و حذف رو ميتونين اجراء 
    كنين ، همچنين با كليك روي سطر مورد نظرتون از Grid عكس ذخيره شده در اون سطر نمايش
    داده ميشه .

تا حد امكان سعي كردم فرايندهاي مختلف برنامه رو در قالب توابع از هم جدا كنم تا براي استفاده
مجدد از اونها مشكلي نداشته باشيد . اميدوارم اين برنامه كمكتون كنه .
موفق باشيد .

----------


## parniant

با سلام به شما شروین عزیز از برنامتون هم ممنونم 
فقط یک مشکلی که هست این هست که من باید با توجه به نام و نام خانوادگی طرف (البته می شه فقط تنها با idاو هم انجام بدم )عمل بازیابی عکسش رو انجام بدم آیا می تونید در این زمینه بهم کمک کنید یعنی با وارد کردن نام و نام خانوادگی طرف و زدن مثلا یک دکمه عکسش رو نشون بده ( برای صدور کارت ) 
با تشکر

----------


## shervin farzin

سلام
فرض كنين نام و نام خانوادگي فرد مورد نظر رو داخل Edit1 و Edit2 وارد كردين و عكسشو
ميخواين داخل Image1 ببينيد .
يه دكمه روي فرمتون بذارين و اين كد رو براش بنويسيد :
var
  pic:TJPEGImage;
  stream:TStream;
begin
with ADOQuery1 do
  begin
    sql.Text:='select * from personel where f_name = :p1 and l_name = :p2';
    Parameters.ParamByName('p1').Value:=edit1.Text;
    Parameters.ParamByName('p2').Value:=edit2.Text;
    Open;
  end;
pic:=TJPEGImage.Create;
stream:=ADOQuery1.CreateBlobStream(ADOQuery1.Field  ByName('pic'),bmRead);
if stream.Size<>0 then
  begin
    pic.LoadFromStream(stream);
    image1.Picture.Assign(pic);
  end
else
  image1.Picture.Graphic:=nil;
stream.Free;
pic.Free;


البته اين رو هم اضافه كنم كه جستجو بر اساس فقط نام و نام خانوادگي ممكن بيشتر از يك
نفر رو برگردونه ( مشابهت نام ) ، اين كد كه من نوشتم فقط عكس اولين نفر رو برميگردونه .
اگه بخواين تمام موارد رو پوشش بده فقط كافيه عمل Select رو انجام بدين ( مثل همين Select
كه من اول اين كد بالا نوشتم ) اون وقت نتيجه اين Select رو كاربر روي Grig ميبينه و با انتخاب
هر كدوم عكسش نمايش داده ميشه ( مثل كاري كه توي برنامه Save Picture ديديد )
موفق باشيد .

----------


## parniant

با سلام 
در قسمت load



> procedure TForm1.Load_pic;
> var
>   pic:TJPEGImage;
>   stream:tstream;
> begin
> pic:=TJPEGImage.Create;
> Stream:=ADOQuery1.CreateBlobStream(ADOQuery1.Field  ByName('pic'),bmRead);
> if stream.Size<>0 then
>   begin
> ...


چون من از دلفی 6 استفاده می کنم نوع TJPEGImage رو برای pic نمی شناسه باید از چه نوعی استفاده کنم 
باتشکر

----------


## parniant

با سلام 
من برای بازیابی عکس از دستور زیر 



> var
>   pic:TJPEGImage;
>   stream:TStream;
> begin
> frmsabt.Image2.Stretch:=true;
> with ADOQuery4 do
>   begin
>     sql.Text:='select * from tteacher where ido= :p1';
>     Parameters.ParamByName('p1').Value:=ComboBox3.Text  ;
> ...


استفاده می کنم اگه بخوام در هنگام ذخیره عکس ، عکس های با پسوند gif رو هم ذخیره کنم در هنگام بازیابی از چه دستوراتی در وسط این دستور استفاده کنم

----------


## shervin farzin

سلام
براي استفاده از تصاوير GIF بايد ابتدا در بخش Uses فرمتون ، GIFImg رو اضافه كنيد .
بعدش توي همين كد Load كه نوشته بوديد هر جا نوشتين TJpegImage ، اونو با
TGIFImage عوض كنيد .
در مورد وضعيت نوع TJPEGImage بايد خدمتتون بگم اين نوع داده از انواع ارائه شده در كلاس
JPEG هست و تا زماني كه شما اين كلاس رو Uses نكنيد در اختيارتون قرار نميگيره ، اما اگه اين
كلاس رو در بخش Uses نوشتيد و همچنان چنين نوع داده اي رو نمي بينيد متاسفانه در مورد
نوع داده مشابه در دلفي 6 من اطلاعاتي ندارم تا به شما كمك كنم .
موفق باشيد .

----------


## mrm0101

سلام . 

از کامپت Developer Express  استفاده کنید . نیاز به کد نویسی ندارد 
cxDBImage از فرمت jepg  پشتیابنی می کند .

----------


## parniant

با سلام 
شروین عزیز می شه بگید در اون قطعه برنامه ای که نوشته بودید برای ویرایش که از این دستور استفاده کرده اید 



> begin
> if (edit1.Text<>'') or (edit2.Text<>'') then
>   begin
>     Edit_db(ADOQuery1.FieldByName('id').Value);
>     button1.Click;
>   end
> else
>   showmessage('Error'+#13+'Enter Name and Family');
> end;


در خط



> Edit_db(ADOQuery1.FieldByName('id').Value);


از کجا تشخیص بده که id من برای ویرایش الان چند است در حقیقت باید کدی رو برای ویرایش کردن بگیره اون کد رو کجا گفتین که از کاربر بگیره (اگر هم در تابع procedure TForm1.Edit_db(id: integer); گفتین می شه بگین کدوم خطش است ) با تشکر

----------


## shervin farzin

سلام
همونطور كه در برنامه ملاحظه كرديد عمل ويرايش بعد از انتخاب يك نفر در DBGrid اتفاق ميفته
در OnCreate فرم برنامه تابعي فراخواني شده كه كارش اجراء يك دستور Select هست كه در 
نتيجه خروجي اين Select كه محتويات جدول شماست داخل Dataset قرار ميگيره .
با انتخاب يك سطر از Grid در واقع  Dataset Record Pointer  ( اشاره گري كه در هر لحظه به يكي
از سطر هاي Dataset اشاره ميكنه ) رو به اون خط منتقل كرديد . 
به اين ترتيب ميتونم به محتويات تمام فيلدهاي اون سطر انتخاب شده دسترسي داشته باشم
به عنوان مثال اگه نام فرد رو ميخواستم بايد به اين ترتيب عمل كنم :
ADOQuery1.FieldByName('F_name').Value
كه مقدار F_name رو به صورت String برام بر ميگردونه .
در مورد خاص اين برنامه من براي اجراء فرايند Edit و در واقع اجراء تابع Edit_db نياز به ID فرد
انتخاب شده دارم به همين منظور براي به دست آوردن ID از كد زير استفاده ميكنم :
ADOQuery1.FieldByName('id').Value
اين خط يك مقدار Integer به من برميگردونه كه همون Id فرد انتخاب شده ميشه ، من ميتونستم
اول خروجي اين خط رو در يك متغيير Integer ذخيره كنم و بعد اون متغيير رو به عنوان ورودي به
تابع Edit_db بدم يا مثل كاري كه در كد برنامه ملاحظه كردين مستقيما همين خط رو در ورودي
تابع Edit_db بنويسم .
اميدوارم توضيحم واضح باشه . موفق باشيد

----------


## parniant

با سلام به شما شروین عزیز و سایر دوستان 
می خواستم ببینم چه زمانی لازمه از Bmwrite استفاده کنیم ( به جای bmread در دستوراتمون ) باتشکر

----------

