成人午夜激情影院,小视频免费在线观看,国产精品夜夜嗨,欧美日韩精品一区二区在线播放

用VC實現對超長數據庫字段的操作

2010-08-28 10:49:52來源:西部e網作者:

    數據庫在實際的開發過程中常常需要存儲較大的二進制數據對象,如圖像、音頻文件、視頻文件或其他二進制數據,這些數據稱之為二進制大對象BLOB(Binary Large Object),其存取方式與普通數據有所區別。在數據庫的表中,BLOB實際上是以二進制數據的形式存放的。由于BLOB的特殊性,一般的程序都無法處理它。比如,如果在一張表中存在BLOB,當用access或Database DeskTop(Delphi在帶的數據庫管理工具)等打開它時,BLOB列將只顯示BLOB字樣。至于該列中實際存的是什么數據單靠access(Database DeskTop)是無法得到的。如果在我們編制的程序中,用控件打開一個有BLOB字段的表,效果也一樣。我們的程序無法直接顯示、編輯以及插入BLOB字段?梢,如何處理這種不能直接顯示的二進制形式數據,用常規的方法是不能滿足要求的。

  結合筆者開發的模型庫管理系統,本文以Visual C++ 6.0和access 2003環境下的數據庫為例,介紹利用ADO實現對超長數據庫字段的訪問,包括寫入和讀出。

  設計數據庫

  使用Access2003作為數據庫系統,數據庫名為blob,唯一的一個數據表為blob,如圖1所示。

  \
  圖1

  其中包括四個字段,分別是id(文本),name(文本),data(OLE對象)和suffix(后綴名),其字段類型必須是OLE對象。id作為主鍵,name是該blob文件的文件名,data字段用來保存二進制大對象,suffix是二進制文件的后綴名,可以是rm,avi,bmp,mp3等。

  系統的實現:

  1、SafeArray:

  在對BLOB進行操作時,要用到SAFEARRAY結構。SAFEARRAY是一種結構化的數據類型,包含了一個由其它數據類型的數據元素組成的數組。之所以稱之為安全的數組是因為它包含了每一維的邊界信息,并限制在邊界內進行數組元素的訪問。其Win32定義SAFEARRAY如下:

typedef struct tagSAFEARRAY
{
 unsigned short cDims;
 unsigned short fFeatures;
 unsigned long cbElements;
 unsigned long cLocks;
 void * pvData;
 SAFEARRAYBOUND rgsabound[ 1 ];
} SAFEARRAY;

  這個結構的成員(cDims,cLocks等)是通過API函數來設置和管理的。真正的數據存放在pvData成員中,而SAFEARRAYBOUND結構定義該數組結構的細節。以下就是該結構成員的簡要描述:

成員 描述
cDims 數組的維數
fFeatures 用來描述數組如何分配和如何被釋放的標志
cbElements 數組元素的大小
cLocks 一個計數器,用來跟蹤該數組被鎖定的次數
pvData 指向數據緩沖的指針
rgsabound 描述數組每維的數組結構,其大小是可變的

  rgsabound是一個有趣的成員,它的結構不太直觀。它是數據范圍的數組。該數組的大小依safe array維數的不同而有所區別。rgsabound成員是一個SAFEARRAYBOUND結構的數組--每個元素代表SAFEARRAY的一個維。

typedef struct tagSAFEARRAYBOUND
{
 unsigned long cElements;
 unsigned long lLbound;
} SAFEARRAYBOUND;


  維數被定義在cDims成員中。例如,一個'C'類數組的維數可以是[3][4][5]-一個三維的數組。如果我們使用一個SAFEARRAY來表示這個結構,我們定義一個有三個元素的rgsabound數組--一個代表一維。cDims = 3; SAFEARRAYBOUND rgsabound[ 3 ]; rgsabound[0]元素定義第一維。在這個例子中ILBOUND元素為0,是數組的下界。cElements成員的值等于三。數組的第二維([4])可以被rgsabound結構的第二個元素定義。下界也可以是0,元素的個數是4,第三維也是這樣。


    2、將二進制文件寫入到數據庫:

  由于這個二進制文件可能很大,所以無法將所有內容一次性讀入到內存。我們需要多次讀入,每次可以使用函數CFile::Read()從文件中讀出一個數據包,然后調用Field對象的AppandChrnk()函數將該包讀入數據庫。AppandChrnk()函數包含在Field對象中,原型如下:HRESULT AppendChunk (const _variant_t & Data );從函數原型中可以看到關鍵的問題是我們需把二進制數據賦值給VARIANT類型的變量。實現的關鍵代碼如下:

while(1)
{ uIsRead=f.Read(bVal,ChunkSize);
 if(uIsRead==0) break;
  rgsabound[0].cElements =uIsRead; rgsabound[0].lLbound = 0;
  psa = SafeArrayCreate(VT_UI1,1,rgsabound); ///創建SAFEARRAY對象
 for(long index=0;index<UISREAD;INDEX++)
  SafeArrayPutElement(psa,&index,&bVal[index]);
  varChunk.vt = VT_ARRAY|VT_UI1;
  varChunk.parray = psa;
  //加入BLOB類型的數據
  m_pRecordset->Fields->GetItem("data")->AppendChunk(varChunk);
  ::VariantClear(&varChunk);
  ::SafeArrayDestroyData( psa);
  if(uIsRead<<CHUNKSIZE) break;
}

  我們所有的讀入數據工作都在一個while循環中實現,每次讀入一個數據包,直到讀完這個數據,即數據量為二進制數據的長度ChunkSize。其中*pBuf為指向緩沖區指針,即要讀入的數據包。ChunkSize為VARIANT變量,用于保存二進制數據,psa是指向安全數組SAFEARRAY的指針。

  3、從數據庫讀出二進制對象到文件:

  同樣,由于這個二進制對象可能很大,無法將所有內容一次性讀入內存中對應于保存數據時我們所使用的AppendChunk函數,讀取數據應該使用GetChunk函數,GetChunk的原型如下:

  _variant_t GetChunk (long Length );唯一的參數Length代表需要讀取的字節數。

  實現的關鍵代碼如下:

long lBlobSize = m_pRecordset->Fields-> Item["data"] ->ActualSize;
while(lBlobSize>0)
{
 lIsRead= lBlobSize >=ChunkSize? ChunkSize: lBlobSize;
 //從字段data中獲取一個數據包
 varChunk = m_pRecordset->Fields->Item["data"]->GetChunk(lIsRead);
 for(index=0;index<LISREAD;INDEX++)
  ::SafeArrayGetElement(varChunk.parray,&index,buf+index);
  //將數據包寫入文件
  f.Write(buf,lIsRead);
  lBlobSize -=lIsRead;
}

  其中f是一個CFile對象,代表了要存儲的文件。Long型變量lBlobSize記錄了二進制對象的大小。利用一個while循環,每次從數據庫中讀取lIsRead字節,直至將其全部讀出。

  結束語

  由于信息技術的飛速發展,特別是多媒體技術的廣泛運用,可以預見,以后數據庫中大對象的應用將日益普遍,有關大對象的存取勢必將是數據庫技術的一個發展方向。本文討論了二進制大對象BLOB在數據庫中的存儲與讀取的VC實現,能夠滿足基本的系統要求,具備了一定的可移植性,為今后更廣泛的應用和更深入的研究提供的借鑒基礎。

關鍵詞:VC

贊助商鏈接:

主站蜘蛛池模板: 舞钢市| 尖扎县| 固始县| 伊宁县| 灵石县| 珠海市| 行唐县| 阿尔山市| 遂溪县| 蒙自县| 子洲县| 巫溪县| 海口市| 孙吴县| 静海县| 瓮安县| 称多县| 兴山县| 永德县| 萝北县| 米易县| 浦县| 丰宁| 阳曲县| 郸城县| 遵义县| 云南省| 剑阁县| 孟津县| 拉萨市| 屯昌县| 黑龙江省| 江西省| 沾益县| 南岸区| 密山市| 东安县| 台东县| 三门县| 茌平县| 都江堰市|