在VC下采用ADO實現BLOB(Binary)數據的存儲,讀取,修改,刪除

在VC下采用ADO實現BLOB(Binary)數據的存儲,讀取,修改,刪除。

 

作者:邵盛鬆 2009-09-05

 

前言

1關於的BLOB(Binary)數據的存儲和讀取功能主要參考了MSDN上的一篇《AppendChunk and GetChunk Methods Example (VC++)》,原文地址是http://msdn.microsoft.com/en-us/library/ms807920.aspx。還有www.vckbase.com上有一篇文章《使用ADO實現BLOB數據的存取 -- ADO開發實踐之二》,原文地址是http://www.vckbase.com/document/viewdoc/?id=252  

我在這篇博文當中增加了對BLOB(Binary)數據的存儲,讀取代碼的分析。

2關於BLOB(Binary)數據的修改,我試驗過多種方法,這個問題也花了比較長的時間纔得到解決,原來的方法是從文件讀取的數據,將更改的數據轉化爲CString類型,然後採用SQL的UPDATE語句進行數據的更新。後來在CSDN論壇上得到了vieri_ch的幫助,問題得到了比較好的一種解決方案。

 

二 實現方法:

1  BLOB(Binary)數據的存儲,將一個文件存儲到數據庫。

存儲部分代碼分析寫的比較詳細,因爲這裏面得一些COM 結構和API需要說明一下

m_pRs爲_RecordsetPtr類型

CFile   fileAdd;  

if(fileAdd.Open(要存儲文件的路徑,CFile::modeRead)==0)    //打開文件

return;   

_variant_t   varChunk;  

long   nLength   =   fileAdd.GetLength();  

BYTE*   pbuf;

pbuf   =   new   BYTE[nLength];  

if(pbuf==NULL)  

return;                  

fileAdd.Read(pbuf,nLength); 

BYTE   *pBufEx;  

pBufEx   =   pbuf;  

SAFEARRAY*   psa;  

SAFEARRAYBOUND   rgsabound[1];  

rgsabound[0].lLbound   =   0;  

rgsabound[0].cElements   =   nLength;  

psa   =   SafeArrayCreate(VT_UI1, 1, rgsabound);  

for   (long   i   =   0;   i   <   nLength;   i++)  

SafeArrayPutElement(psa,&i, pBufEx++);  

VARIANT   varBLOB;  

varBLOB.vt   =   VT_ARRAY   |   VT_UI1;  

varBLOB.parray   =   psa;

m_pRs->ADOFields->GetItem(_variant_t("BLOB類型字段的名稱"))->AppendChunk(varBLOB);

m_pRs->Update();

m_pRs->Close();

 

在代碼中有一個SAFEARRAY和SAFEARRAYBOUND類型,該類型在頭文件OAIdl.h中定義

typedef struct tagSAFEARRAY

{

USHORT cDims;

USHORT fFeatures;

ULONG cbElements;

ULONG cLocks;

SAFEARRAYBOUND rgsabound[ 1 ];

}SAFEARRAY;

SAFEARRAY結構體中包含了SAFEARRAYBOUND類型。

先說SAFEARRAYBOUND結構

cElements表示數組中元素的個數。

lLbound表示數組的下界。

代碼中SAFEARRAYBOUND元素個數爲讀取文件的大小,下界是0

操作SAFEARRAY類型是由COM提供了一套API來處理的。oleauto.h 頭文件中可以看到很多關於操作SAFEARRAY數據類型的API.以下少列出幾個

WINOLEAUTAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY ** ppsaOut);

WINOLEAUTAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY ** ppsaOut);

WINOLEAUTAPI SafeArrayAllocData(SAFEARRAY * psa);

WINOLEAUTAPI_(SAFEARRAY *) SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND * rgsabound);

 

SAFEARRAY爲什麼會稱爲安全數組?

從名字上看是安全數組的意思。比如我們第一個數組,數組的大小爲10,數組的下界是從0開始,這時我們訪問下界爲10的元素,這時就發生了錯誤,以爲數組的下界最大爲9。SAFEARRAY這樣定義結構的作用是實現COM API函數可以限制我們訪問下界爲10的元素和其他一些安全操作數組的行爲等

SAFEARRAY結構說明

成員 描述

cDims 數組的維數

fFeatures 標誌

cbElements 數組元素的大小

cLocks 一個計數器,用來跟蹤該數組被鎖定的次數

pvData  指向數據緩衝的指針

標誌表示是在堆上創建還是在棧上創建等還包括其他一些標誌

 

FADF_AUTO 0x0001

 在棧上創建數組

FADF_STATIC 0x0002

 在堆上創建數組

FADF_EMBEDDED 0x0004

 在結構中創建

FADF_FIXEDSIZE 0x0010

 不能改變數組大小

FADF_RECORD 0x0020

 記錄容器

FADF_HAVEIID 0x0040

 有IID 身份標記 數組

FADF_HAVEVARTYPE 0x0080

 VT 類型數組

FADF_BSTR 0x0100

 BSTR數組

FADF_UNKNOWN 0x0200

 IUnknown* 數組

FADF_DISPATCH 0x0400

 IDispatch* 數組

FADF_VARIANT 0x0800

 VARIANTs數組

FADF_RESERVED 0xF0E8

 餘留,將來使用

COM API函數說明SafeArrayCreate創建數組。參數VT_UI1是表示unsigned int 1字節整數(BYTE)數組

vt是數組類型、lLbound是數組下界值(最小下標)和數組長度

 

SafeArrayPutElement函數是向一個安全數組中添加一個值,代碼中採用循環一個一個得添加

 

ADO方法

AppendChunk將數據追加到大型文本、二進制數據 Field 或 Parameter 對象。

語法

object.AppendChunk Data

參數

object   Field 或 Parameter 對象

Data  變體型,包含追加到對象中的數據。

 

2  BLOB(Binary)數據的讀取

將數據庫中的數據讀出並寫入文件。

long   lDataLength = m_pRs->GetFields()->GetItem(_variant_t("BLOB類型的字段"))->ActualSize;

if (lDataLength>0)

{

_variant_t   varBLOB;  

varBLOB=m_pRs->GetFields()->GetItem(_variant_t("BLOB類型的字段"))->GetChunk(lDataLength);      

if(varBLOB.vt== (VT_ARRAY|VT_UI1) && varBLOB.vt!=VT_EMPTY && varBLOB.vt!=VT_NULL )                

{

BYTE   *pBuf   =   NULL;        

pBuf   =   (BYTE*)GlobalAlloc(GMEM_FIXED,lDataLength);  

SafeArrayAccessData(varBLOB.parray,(void   **)&pBuf);    

      

strFileName表示生成包含文件名的路徑

CFile   outFile(strFileName,CFile::modeCreate|CFile::modeWrite); //構造新文件,如果文件存在,則長度變爲0 

outFile.Write(pBuf,lDataLength);  

outFile.Close();                      

SafeArrayUnaccessData (varBLOB.parray);                                          

       } 

}

m_pRs->Close();

 

3  BLOB(Binary)數據的修改

 

CFileException eFile;

CFile   fileSave;  

strPath表示需要修改文件的路徑

fileSave.Open(strPath,CFile::modeReadWrite|CFile::shareDenyWrite|CFile::shareDenyRead|CFile::typeBinary,&eFile);

_variant_t   varChunk;  

long   nLength   =    fileSave.GetLength();  

BYTE*   pbuf;

pbuf   =   new   BYTE[nLength];  

if(pbuf   == NULL) return;                          

fileSave.Read(pbuf,nLength);

fileSave.Close();

BYTE   *pBufEx;  

pBufEx   =   pbuf;  

SAFEARRAY*   psa;  

SAFEARRAYBOUND   rgsabound[1];  

rgsabound[0].lLbound   =   0;  

rgsabound[0].cElements   =   nLength;  

psa   =   SafeArrayCreate(VT_UI1, 1, rgsabound);  

for   (long   i   =   0;   i   <   nLength;   i++)  

       SafeArrayPutElement(psa,&i, pBufEx++);  

VARIANT   varBLOB;  

varBLOB.vt   =   VT_ARRAY   |   VT_UI1;  

varBLOB.parray   =   psa;

CString strSQL;

strSQL.Format(_T("UPDATE 表名 SET BLOB字段名=? WHERE ID='1'");

m_pCom.CreateInstance(__uuidof(Command));

m_pCom->ActiveConnection = m_pCon;

m_pCom->CommandText = _bstr_t(strSQL);

m_pCom->CommandType = adCmdText;

m_pCom->Parameters->Append(m_pCom->CreateParameter(_T("@參數名"),adVarBinary, adParamInput, -1, varBLOB));

m_pCom->Execute(NULL,NULL,adCmdText);

 

4 BLOB(Binary)數據的修改

 

刪除比較簡單一點,同時表定義該字段允許爲空

執行一個SQL語句就可以了

UPDATE 表名 SET BLOB字段名 = NULL WHERE ID=1

 

以上程序已經在Visual C++2005 Unicode下調試通過

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章