首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC6.0 使用 ADO Stream 物件高效讀寫資料庫 Blob 影像

     編輯:VC 教學

傳統使用 ADO Field 物件的 GetChunk/AppendChunk 讀寫 Blob 需手動分塊處理,程式碼冗長且易出錯。ADO 2.5+ 提供的 Stream 物件可將 Blob 視為二進位串流,支援直接存檔/讀檔、轉換編碼、複製到 IStream 等高階操作,大幅簡化程式碼。本文完整示範從資料庫讀取影像並顯示、以及寫入影像到資料庫的完整流程。

一、核心物件與常數

#import "msado15.dll" no_namespace rename("EOF", "adoEOF")
#include <olectl.h>   // IPicture, OleLoadPicture
#include <comdef.h>  // _variant_t, _bstr_t

// Stream 類型常數
const long adTypeBinary = 1;
const long adModeUnknown = 0;
const long adOpenStreamUnspecified = -1;
const long adSaveCreateOverWrite = 2;
const long adReadAll = -1;

二、從資料庫讀取 Blob 並顯示影像

步驟 1:建立 Stream 並寫入 Blob 資料

_StreamPtr pStm;
pStm.CreateInstance(__uuidof(Stream));
pStm->Type = adTypeBinary;

_variant_t varOptional(DISP_E_PARAMNOTFOUND, VT_ERROR);
pStm->Open(varOptional, adModeUnknown, adOpenStreamUnspecified, _bstr_t(), _bstr_t());

// 假設 m_pRecordset 為已開啟的 Recordset,含 "photo" Blob 欄位
pStm->Write(m_pRecordset->Fields->GetItem("photo")->Value);

步驟 2:另存為檔案(選擇性,支援任意副檔名)

pStm->SaveToFile(_T("C:\\Temp\\photo.jpg"), adSaveCreateOverWrite);
pStm->Close();

步驟 3:不存檔,直接在記憶體轉 IStream 並用 IPicture 繪圖

// 取得 Stream 大小,配置全域記憶體
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, pStm->Size);
LPVOID pvData = GlobalLock(hGlobal);

// 複製 Stream 資料到全域記憶體
// 注意:此處原文有變數名稱錯誤,修正如下
char* pBuf = new char[pStm->Size];
memcpy(pBuf, (char*)pStm->Read(adReadAll), pStm->Size); // 簡化複製
memcpy(pvData, pBuf, pStm->Size);
delete[] pBuf;

GlobalUnlock(hGlobal);

// 建立 IStream
IStream* pStream = nullptr;
CreateStreamOnHGlobal(hGlobal, TRUE, &pStream); // TRUE: 釋放時自動釋放 hGlobal

// 載入 IPicture
IPicture* pPic = nullptr;
if (SUCCEEDED(OleLoadPicture(pStream, pStm->Size, TRUE, IID_IPicture, (LPVOID*)&pPic))) {
    // 取得影像尺寸 (HIMETRIC 單位)
    OLE_XSIZE_HIMETRIC hmWidth;
    OLE_YSIZE_HIMETRIC hmHeight;
    pPic->get_Width(&hmWidth);
    pPic->get_Height(&hmHeight);

    // 轉換為裝置像素
    CDC* pDC = GetDC(); // 或傳入的 CDC*
    double fX = (double)pDC->GetDeviceCaps(HORZRES) * hmWidth / ((double)pDC->GetDeviceCaps(HORZSIZE) * 100.0);
    double fY = (double)pDC->GetDeviceCaps(VERTRES) * hmHeight / ((double)pDC->GetDeviceCaps(VERTSIZE) * 100.0);

    // 繪製至 (0,0)
    pPic->Render(*pDC, 0, 0, (long)fX, (long)fY, 0, hmHeight, hmWidth, -hmHeight, NULL);
    pPic->Release();
}
pStream->Release();

關鍵點:IPicture 支援 BMP、JPG、GIF、PNG 等多種格式,無需自行解碼。

三、從檔案寫入 Blob 到資料庫

_StreamPtr pStm;
pStm.CreateInstance(__uuidof(Stream));
pStm->Type = adTypeBinary;
pStm->Open(varOptional, adModeUnknown, adOpenStreamUnspecified, _bstr_t(), _bstr_t());

// 直接載入檔案
pStm->LoadFromFile(_T("C:\\Images\\product.gif"));

// 讀取全部位元組陣列
_variant_t varBlob = pStm->Read(adReadAll);

// 寫入 Recordset
m_pRecordset->Fields->GetItem("photo")->Value = varBlob;
m_pRecordset->Update();

四、常見問題與優化

  • 記憶體洩漏:所有 COM 介面(_StreamPtr、IPicture*、IStream*)皆為智慧指標或需手動 Release,確保配對。
  • 大檔案處理:Stream 內部採用記憶體對應,超大 Blob(>100MB)建議分塊 Read/Write 或直接 SaveToFile/LoadFromFile 避免記憶體壓力。
  • 編碼轉換:Stream 亦支援 adTypeText 與 Charset 屬性,可處理 XML/JSON 文字型 Blob。
  • 錯誤處理:包裹 _com_error 捕獲 ADO/COM 例外,記錄 ErrorDescription。

五、擴充應用

同樣架構可輕鬆擴充至:

  • 資料庫備份/還原 Blob 欄位批次匯出入檔案。
  • 讀取 XML Blob 直接餵給 MSXML 解析。
  • 串流式傳輸大型二進位資料至網路/壓縮/加密元件。

掌握 ADODB.Stream 讓 Blob 操作從「痛苦的分塊迴圈」變成「幾行流暢程式碼」,是 VC++ 資料庫開發的必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved