1 、引言
在許多項(xiàng)目開(kāi)發(fā)中,由于存在著大量的數(shù)據(jù)需要存儲(chǔ),通常采用數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)這些數(shù)據(jù),使得數(shù)據(jù)庫(kù)技術(shù)被越來(lái)越廣泛地應(yīng)用。在這些數(shù)據(jù)中有簡(jiǎn)單的文本文件,只需通過(guò)api的簡(jiǎn)單編程即可實(shí)現(xiàn),但也存在許多大對(duì)象數(shù)據(jù),比如圖像、音頻和視頻等,其存儲(chǔ)形式有所不同。作為大對(duì)象數(shù)據(jù)的圖像數(shù)據(jù),一般以blob(二進(jìn)制大對(duì)象,binary large object)形式存儲(chǔ),例如access數(shù)據(jù)庫(kù)中ole對(duì)象數(shù)據(jù)類型、sql server數(shù)據(jù)庫(kù)中的image數(shù)據(jù)類型等。在vc++ 7.0的環(huán)境下,為了高效快捷的訪問(wèn)圖像數(shù)據(jù),需要采用合適的數(shù)據(jù)庫(kù)訪問(wèn)技術(shù)。
在vc++中標(biāo)準(zhǔn)的訪問(wèn)數(shù)據(jù)庫(kù)技術(shù)有很多種,根據(jù)開(kāi)發(fā)的項(xiàng)目,采用了數(shù)據(jù)庫(kù)技術(shù)中最常見(jiàn)有效的兩種技術(shù)ado技術(shù)和mfc odbc在access數(shù)據(jù)庫(kù)中訪問(wèn)圖像數(shù)據(jù)。
2、 圖像數(shù)據(jù)訪問(wèn)原理
雖然圖像數(shù)據(jù)的格式有多種,例如bmp、jpg和gif等格式,但都可以看成是二進(jìn)制流,即blob類型。blob類型數(shù)據(jù)需要占用較大的硬盤(pán)空間和內(nèi)存,對(duì)存儲(chǔ)效率和查詢速度都有很大的影響。
圖像數(shù)據(jù)的訪問(wèn)分存儲(chǔ)和讀取兩個(gè)過(guò)程。在存儲(chǔ)過(guò)程中,由于存放圖像數(shù)據(jù)的字段是可變長(zhǎng)度(長(zhǎng)度一般為0~2g)的blob類型,無(wú)法直接存儲(chǔ),必須首先將存儲(chǔ)在文件中的圖像數(shù)據(jù)以二進(jìn)制流的形式讀到緩沖區(qū)中,然后再將緩沖區(qū)中的圖像數(shù)據(jù)添加到access數(shù)據(jù)庫(kù)中的ole對(duì)象中。在讀取過(guò)程中,將存放在access數(shù)據(jù)庫(kù)中的圖像數(shù)據(jù)讀到緩沖區(qū)中,然后在顯示在用戶界面上。圖像數(shù)據(jù)的訪問(wèn)原理如圖1所示。
圖1 圖像數(shù)據(jù)訪問(wèn)原理圖
3、 應(yīng)用ado訪問(wèn)圖像數(shù)據(jù)
3.1 ado的介紹
ado(activex data objects)是microsoft數(shù)據(jù)庫(kù)應(yīng)用程序開(kāi)發(fā)的接口,是建立在ole db技術(shù)之上的高層數(shù)據(jù)庫(kù)訪技術(shù),簡(jiǎn)化了編程,且有利于程序的可移植性及可擴(kuò)充性。
ado包括connection對(duì)象、command對(duì)象、parameter對(duì)象、recordset對(duì)象、field對(duì)象、error對(duì)象、property對(duì)象以及相應(yīng)的集合對(duì)象,這些對(duì)象被封裝在_connection -ptr接口、_commndptr接口和_recordsetptr接口這三個(gè)基本接口中。
3.2 ado連接數(shù)據(jù)庫(kù)
(1) 導(dǎo)入ado庫(kù)
使用ado前需要在stdafx.h頭文件中導(dǎo)入該庫(kù),只需利用import指令將此動(dòng)態(tài)鏈接庫(kù)導(dǎo)入,具體代碼如下:
#import“c:program filescommon filessystemadomsado15.dll”o_namespaceename(“eof”,“adoeof”)
(2) 初始化com庫(kù)
ado本身是一個(gè)com組件,在使用時(shí)需要初始化com庫(kù),需要調(diào)用coinitialize函數(shù)來(lái)實(shí)現(xiàn)。
:: coinitialize(null);
(3) 創(chuàng)建connection對(duì)象并連接數(shù)據(jù)庫(kù)
創(chuàng)建connection對(duì)象:
_connectionptr m_pconnection;
m_pconnection.createinstanc -e(“adodb.connection”);
連接數(shù)據(jù)庫(kù):
_pconnection-》open(“provide -r=microsoft.jet.oledb.4.0;datasource = picture.mdb”, “”,“”, admodeunknown);
(4) 執(zhí)行操作
m_precordset.createinstance(“adodb.recordset”);
m_precordset-》open((_variant_t)strsql,_variant_t((idispatch*)theapp.m_pconnection,true),adopendynamic,adlockoptimistic,adcmdtext);
3.3 圖像數(shù)據(jù)的存儲(chǔ)
對(duì)于一般數(shù)據(jù),可以通過(guò)recordset對(duì)象的getcollect()和putcollect()函數(shù)來(lái)對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ)和讀取,而對(duì)于圖像數(shù)據(jù),就需要使用field對(duì)象中的appendchunk函數(shù)來(lái)進(jìn)行存儲(chǔ)和getchunk函數(shù)來(lái)進(jìn)行讀取。圖像數(shù)據(jù)的存儲(chǔ)過(guò)程可以分為以下三步:
(1) 打開(kāi)圖像數(shù)據(jù),獲得數(shù)據(jù)長(zhǎng)度;申請(qǐng)緩沖區(qū),把文件讀入此緩沖區(qū)。
(2) 構(gòu)造一個(gè)一維數(shù)組,把緩沖區(qū)中的數(shù)據(jù)拷貝到數(shù)組中,然后構(gòu)造一個(gè)變體對(duì)象,用數(shù)組來(lái)對(duì)此對(duì)象賦值。
(3) 調(diào)用appendchunk函數(shù),把數(shù)據(jù)存入recordset對(duì)象的本地緩沖區(qū)。
具體實(shí)現(xiàn)代碼如下:
if(m_pic.m_ipicture != null) m_pic.freepicturedata();
if(f.open(m_strphotopath, cfile::moderead |
cfile::typebinary, &e)) //打開(kāi)了一個(gè)圖像文件
{nsize = f.getlength();//先得到圖像數(shù)據(jù)長(zhǎng)度
byte * pbuffer = new byte [nsize];//根據(jù)數(shù)據(jù)的長(zhǎng)度申請(qǐng)緩沖區(qū)
if (f.read(pbuffer, nsize) 》 0 )//把圖像數(shù)據(jù)讀到緩沖區(qū)
{byte *pbuf = pbuffer;//把pbuffer里的jpg數(shù)據(jù)放到庫(kù)中
variant varblob;
safearray *psa;
safearraybound rgsabound[1];//創(chuàng)建safearray對(duì)象
if(pbuf)
{rgsabound[0].llbound = 0;
rgsabound[0].celements = nsize;
psa = safearraycreate(vt_ui1, 1, rgsabound);
for (long i = 0; i 《 (long)nsize; i++)safearrayputelement (psa, &i, pbuf++);
varblob.vt = vt_array | vt_ui1;
varblob.parray = psa;
m_precordset-》getfields()-》getitem(“picture”)-》appendchunk(varblob);
m_precordset-》update();//更新數(shù)據(jù)庫(kù)
}
delete [] pbuffer; //釋放緩沖區(qū)
pbuf=0;
}
f.close();
}
3.4 圖像數(shù)據(jù)的讀取
圖像數(shù)據(jù)的讀取過(guò)程可以分為以下三歩:
(1) 獲得picture字段中圖像文件的實(shí)際長(zhǎng)度。
(2) 調(diào)用getchunk函數(shù),返回變體對(duì)象。
(3) 獲得數(shù)組數(shù)據(jù)指針,把數(shù)據(jù)寫(xiě)入打開(kāi)的文件中。
具體實(shí)現(xiàn)代碼如下:
long nsize=m_precordset-》getfields()-》getitem(“picture ”)-》actualsize;//獲得圖像文件的長(zhǎng)度
if(nsize1 》 0)
{ varblob=m_precordset-》getfields()-》getitem
(“picture ”)-》getchunk(nsize);//獲得varblob的值
if(varblob.vt == (vt_array | vt_ui1))
{char *pbuf = null;
lpvoid pbuf2 = null;
safearrayaccessdata(varblob.parray,
(void **)&pbuf);//獲得數(shù)組數(shù)據(jù)指針
hglobal=globalalloc(gmem_moveable,nsize);
pbuf2 = globallock(hglobal);
memcpy(pbuf2,pbuf,nsize1);//復(fù)制數(shù)據(jù)到緩沖區(qū)
::globalunlock(hglobal);
safearrayunaccessdata (varblob.parray);
hr=::createstreamonhglobal( hglobal,true, &pstream );
hr=::oleloadpicture( pstream, nsize1, true, iid_ipicture, (lpvoid * )&ppicture );
ppicture-》render(pdc-》m_hdc,0,0,rect.width(),rect.height(),0,nheight,nwidth,-nheight,null);//將圖像數(shù)據(jù)顯示在用戶界面
}
}
4 、應(yīng)用mfc odbc訪問(wèn)圖像數(shù)據(jù)
4.1 mfc odbc的介紹
odbc(open database connect-ivity)是微軟公司開(kāi)放服務(wù)結(jié)構(gòu)中有關(guān)數(shù)據(jù)庫(kù)的一個(gè)組成部分。mfc的odbc類對(duì)較復(fù)雜的odbcapi進(jìn)行了封裝,提供了簡(jiǎn)化的調(diào)用接口,方便了數(shù)據(jù)庫(kù)應(yīng)用程序的開(kāi)發(fā)。
mfcodbc類主要包括cdatabase類、crecordset類和cfieldexchange類。cdatabase類的主要功能是建立與數(shù)據(jù)庫(kù)的連接;crecordset類針對(duì)數(shù)據(jù)源中記錄集,它負(fù)責(zé)對(duì)記錄的操作;cfieldexchange類負(fù)責(zé)crecordset與數(shù)據(jù)源的數(shù)據(jù)交換。
4.2 配置odbc數(shù)據(jù)源
用odbc管理器定義了一個(gè)數(shù)據(jù)源,管理器根據(jù)數(shù)據(jù)源所在的位置,數(shù)據(jù)庫(kù)類型及odbc驅(qū)動(dòng)器等信息,建立起odbc與具體數(shù)據(jù)庫(kù)之間的聯(lián)系。在windowsxp的系統(tǒng)中,配置odbc數(shù)據(jù)源的過(guò)程為:控制面板—性能和維護(hù)—管理工具—數(shù)據(jù)源(odbc)。
4.3 odbc連接數(shù)據(jù)庫(kù)
創(chuàng)建cdatabase對(duì)象并連接數(shù)據(jù)庫(kù):
cdatabase m_db;//定義的數(shù)據(jù)庫(kù)全局變量
cbitmap bitmap;//定義的圖像類全局變量,存儲(chǔ)圖像數(shù)據(jù)
m_db.open(null, false, false, “odbc;driver={microsoft accessdriver (*.mdb)};
dbq= picture.mdb”);
4.4 圖像數(shù)據(jù)的存儲(chǔ)
首先做一些變量的定義:
m_ picture為picture字段對(duì)應(yīng)的長(zhǎng)二進(jìn)制成員變量;
m_hdata用來(lái)存放picture字段的數(shù)據(jù);
m_dwdatalength為picture字段的實(shí)際長(zhǎng)度。
圖像數(shù)據(jù)的存儲(chǔ)過(guò)程可以分為以下三步:
(1) 打開(kāi)圖像數(shù)據(jù),獲得數(shù)據(jù)長(zhǎng)度;
(2) 申請(qǐng)緩沖區(qū),把文件讀入此緩沖區(qū);
(3) 通過(guò)調(diào)用update()刷新數(shù)據(jù)庫(kù)記錄。
具體實(shí)現(xiàn)代碼如下:
static char based_code s***ilter[]=“bitmap files(*.bmp)|*.bmp||”;
cdbimages dbimages(m_db);
cfiledialog fd(true,null,null,0,s***ilter,this);
if (idok != fd.domodal()) return;
dbimages.open();
dbimages.addnew();
cfile fileimage;
cfilestatus filestatus;
fileimage.open(fd.getpathname(), cfile::moderead);
fileimage.getstatus(filestatus);//獲得打開(kāi)圖像文件的狀態(tài)
dbimages.m_ picture.m_dwdatal -ength =filestatus.m_size;
hglobal hglobal=globalalloc(gptr,filestatus.m_size);//分配內(nèi)存
dbimages.m_ picture.m_hdata = globallock(hglobal);//鎖定內(nèi)存
fileimage.readhuge(dbimages.m_picture.m_hdata,filestatus.m_size);//向緩沖區(qū)讀取圖像數(shù)據(jù)
dbimages.setfielddirty(&dbimages.m_ picture);//修改標(biāo)志數(shù)據(jù)庫(kù)
dbimages.setfieldnull(&dbim -ages.m_ picture,false);
dbimages.update();//刷新數(shù)據(jù)庫(kù)的記錄
globalunlock(hglobal);
dbimages.close();
4.5 圖像數(shù)據(jù)的讀取
圖像數(shù)據(jù)的讀取過(guò)程可以分為以下三步:
(1) 定義臨時(shí)文件。
(2) 向臨時(shí)文件中存放從數(shù)據(jù)庫(kù)中讀取到的圖像數(shù)據(jù)。
(3) 取出圖像數(shù)據(jù),獲得圖像數(shù)據(jù)的寬度和高度。
具體實(shí)現(xiàn)代碼如下:
cdbimages dbimages(m_db);
cstring strfilename ;
i=1;
strfilename.format(“%s”,i)dbimages.open();
if (dbimages.iseof())afxmessagebox(“unable to get image from picture”);
else{char tmppath[_max_path 1];
gettemppath(_max_path,tmppath);
strfilename.insert(0,tmppath);
cfile outfile(strfilename,cfile::modecreate
|cfile::modewrite);
lpstr buffer=(lpstr)globallock(dbimages.m_ picture.m_hdata);
outfile.writehuge(buffer,dbima -ges.m_picture.m_dwdatalength);
globalunlock(dbimages.m_ picture.m_hdata);
outfile.close();
hbitmap hbm=(hbitmap)::loa -dimage(null,strfilename,image_bitmap, 0, 0, lr_loadfromfile);
if (bitmap.attach(hbm)) { bitmap bm;
bitmap.getbitmap(&bm); //獲得圖像的尺寸
bitmap.setbitmapdimension(bm.bmwidth,bm.bmheight);//獲得圖像的寬度和高度
}
5 、結(jié)束語(yǔ)
介紹了使用ado技術(shù)和mfcodbc在access中存儲(chǔ)和讀取圖像數(shù)據(jù)的方法以及部分程序代碼。這兩種訪問(wèn)方法在vc++7.0的環(huán)境下進(jìn)行調(diào)試結(jié)果顯示,使用ado來(lái)訪問(wèn)數(shù)據(jù)庫(kù)中的圖像數(shù)據(jù)更加的方便,更加的高效,使用mfcodbc方法訪問(wèn)大對(duì)象數(shù)據(jù)的速度相對(duì)較慢。在開(kāi)發(fā)擴(kuò)展時(shí)會(huì)發(fā)現(xiàn)mfcodbc不能用于其他的非關(guān)系數(shù)據(jù)庫(kù),使用的范圍相對(duì)較窄。這兩種方法還可以應(yīng)用于其他二進(jìn)制大對(duì)象數(shù)據(jù)的訪問(wèn)。
責(zé)任編輯:gt
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6819瀏覽量
88746 -
視頻
+關(guān)注
關(guān)注
6文章
1930瀏覽量
72774 -
存儲(chǔ)
+關(guān)注
關(guān)注
13文章
4228瀏覽量
85580
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論