【備注】本文中所闡述代碼應用于我為BS架構業務系統開發的某個 ActiveX 控件中。
我們将向一個典型SQL資料庫中的某表的 Image 類型的字段(假設字段名稱為“PHOTO”)存儲一副圖檔,實際上 Image 字段是一種二進制流,它是由應用程式負責解釋的。是以在這裡我們是将其當作 jpg 圖像檔案。換句話說,把 jpg 檔案的原始位元組流存儲到 Image 字段中去。由于通過記憶體中轉,這種檔案的尺寸不宜過大。
我們假設在一個CImage對象中已經加載的就是要儲存的圖檔,同時也打開了相應表的一個用于插入記錄的記錄集指針 (_RecordsetPtr )。
則相關代碼如下:

代碼
//存儲圖檔
bool SaveImage(CImage *lpImg, _RecordsetPtr pRecordset, char* errormsg)
{
//估算圖像需要的記憶體大小,這裡當作 BMP 格式來估算的,是以結果比實際需要的更大。
SIZE_T buffersize = lpImg->GetWidth() * lpImg->GetHeight() * lpImg->GetBPP()/8 + sizeof(BITMAPINFO);
HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, buffersize);
if(hMem != NULL)
{
IStream* pStream = NULL;
CreateStreamOnHGlobal(hMem, FALSE, &pStream);
if(pStream != NULL)
{
LARGE_INTEGER temp;
ULARGE_INTEGER fileLength;
temp.QuadPart = 0;
lpImg->Save(pStream); //寫入記憶體流
//擷取目前檔案的位置
pStream->Seek(temp, STREAM_SEEK_CUR, &fileLength);
ULONG nLength = (ULONG)(fileLength.QuadPart+1);
SAFEARRAY* psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = nLength;
//VT_UI1 : Variable type is unsigned char.
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
//鎖定記憶體
BYTE *lpBytes = (BYTE*)GlobalLock(hMem);
BYTE *lpTemp = lpBytes;
for (LONG i = 0; i < nLength; i++)
SafeArrayPutElement (psa, &i, lpTemp++);
//解鎖記憶體
GlobalUnlock(hMem);
VARIANT varBLOB;
varBLOB.vt = VT_ARRAY | VT_UI1;
varBLOB.parray = psa;
//存儲
pRecordset->Fields->GetItem("PHOTO")->AppendChunk(varBLOB);
pStream->Release();
//
SafeArrayDestroyData(psa);
}
else
GlobalFree(hMem);
sprintf(errormsg, "CreateStreamOnHGlobal Failed");
return false;
//釋放全局記憶體
GlobalFree(hMem);
}
else
sprintf(errormsg, "GlobalAlloc Failed!");
return false;
return true;
}
下面再列舉一下,如何從 image 字段中讀取内容,并把它儲存到一個磁盤上的普通檔案。假設表具有一個自增的數字主鍵(“ID”)。

代碼_ReadImage
//id:主鍵
void ReadImg(int id)
_RecordsetPtr pRs = NULL;
_ConnectionPtr pConnection = NULL;
_variant_t varChunk;
HRESULT hr;
//連接配接字元串
_bstr_t strCnn("Provider=SQLOLEDB;Server=...;Database=...;User ID=...;Password=...;");
try
//Open a connection
pConnection.CreateInstance(__uuidof(Connection));
hr = pConnection->Open(strCnn,"","",NULL);
pRs.CreateInstance(__uuidof(Recordset));
//表名略
char cmdText[128];
sprintf(cmdText, "select PHOTO from ... where ID = %d", id);
pRs->Open(cmdText,_variant_t((IDispatch *) pConnection,true),adOpenKeyset,adLockOptimistic,adCmdText);
//read data
long lPhotoSize = pRs->Fields->GetItem("PHOTO")->ActualSize;
long llsRead = 0;
_variant_t varChunk;
BYTE buf[ChunkSize];
printf("lDatalength = %ld\n", lPhotoSize);
//儲存到C槽
char filename[128];
sprintf(filename, "C:\\ID_%d.jpg", id);
FILE* stream = fopen(filename, "wb");
while(lPhotoSize > 0)
llsRead = lPhotoSize >= ChunkSize? ChunkSize:lPhotoSize;
varChunk = pRs->Fields->GetItem("PHOTO")->GetChunk(llsRead);
for(long index = 0; index < llsRead; index++)
{
SafeArrayGetElement(varChunk.parray, &index, buf+index);
}
fwrite(buf, 1, llsRead, stream);
lPhotoSize -= llsRead;
fclose(stream);
printf("Save File Complete: %s\n", filename);
pRs->Close();
pConnection->Close();
catch(_com_error &e)
{
// Notify the user of errors if any.
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
CString sError;
sError.Format(_T("Source : %s \n Description : %s\n"),(LPCSTR)bstrSource,(LPCSTR)bstrDescription);
//AfxMessageBox(sError);
//printf("%s\n", sError);