資料庫裡存 Word、Excel、圖片等二進位大物件 (BLOB) 是常見需求。MFC 提供 CLongBinary 類別,配合 RFX/DFX 機制,讓 BLOB 存取變得像操作普通欄位一樣簡單。本文以 SQL Server + ODBC 為例,手把手帶你建立完整範例。
CREATE TABLE REPORT_TABLE (
REGISTER_NUM CHAR(12) NOT NULL PRIMARY KEY,
REPORT_IMAGE VARBINARY(MAX) -- 或 IMAGE 類型 (舊版)
);
在 ODBC 管理員建立系統 DSN ABCDB 指向此資料庫。
CReportRecordSet 繼承 CRecordset → 選 DSN ABCDB → 選資料表 REPORT_TABLECReportFormView 繼承 CRecordView,關聯 CReportRecordSetReportRecordSet.h
// 原:CString m_REPORT;
CLongBinary m_REPORT; // 對應 BLOB 欄位
ReportRecordSet.cpp
// 刪除初始化
// m_REPORT = _T(""); ← 刪除這行
// 修改 RFX 呼叫
// 原:RFX_Text(pFX, _T("[REPORT]"), m_REPORT);
RFX_LongBinary(pFX, _T("[REPORT]"), m_REPORT); // ODBC 用 RFX_LongBinary
// 若用 DAO 則用 DFX_LongBinary
m_pSet->m_REGISTER_NUM
void CReportFormView::OnGetDocument()
{
try {
if (m_pSet->IsEOF()) {
AfxMessageBox(_T("查無資料")); return;
}
CString tmpPath = _T("e:\\temp\\report.doc");
// 清理舊暫存檔
if (GetFileAttributes(tmpPath) != INVALID_FILE_ATTRIBUTES)
DeleteFile(tmpPath);
// 寫入檔案
CFile outFile(tmpPath, CFile::modeCreate | CFile::modeWrite);
LPSTR pData = (LPSTR)GlobalLock(m_pSet->m_REPORT.m_hData);
outFile.WriteHuge(pData, m_pSet->m_REPORT.m_dwDataLength);
GlobalUnlock(m_pSet->m_REPORT.m_hData);
outFile.Close();
// 啟動 Word
ShellExecute(NULL, NULL, tmpPath, NULL, _T("e:\\temp"), SW_SHOW);
}
catch (CException* e) {
e->ReportError(); e->Delete();
}
}
void CReportFormView::OnUpdateDocument()
{
m_pSet->Edit(); UpdateData(TRUE);
CFileDialog dlg(TRUE, _T("doc"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("Word Files (*.doc)|*.doc||"), this);
if (dlg.DoModal() != IDOK) return;
CFile file(dlg.GetPathName(), CFile::modeRead);
CFileStatus fs; file.GetStatus(fs);
m_pSet->m_REPORT.m_dwDataLength = fs.m_size;
HGLOBAL hGlobal = GlobalAlloc(GPTR, fs.m_size);
m_pSet->m_REPORT.m_hData = GlobalLock(hGlobal);
file.ReadHuge(m_pSet->m_REPORT.m_hData, fs.m_size);
file.Close();
m_pSet->SetFieldDirty(&m_pSet->m_REPORT);
m_pSet->SetFieldNull(&m_pSet->m_REPORT, FALSE);
m_pSet->Update();
GlobalUnlock(hGlobal);
AfxMessageBox(_T("更新成功"));
}
void CReportFormView::OnAddDocument()
{
m_pSet->AddNew(); // 唯一差異
// 其餘同 OnUpdateDocument
}
在 ABC.cpp 的 InitInstance 中:
// 原:pDocTemplate->AddView(RUNTIME_CLASS(CAbcView));
pDocTemplate->AddView(RUNTIME_CLASS(CReportFormView));
CLongBinary 內部用 GlobalAlloc,讀寫時必須 GlobalLock/Unlock,否則存取違規。SetFieldDirty + SetFieldNull(..., FALSE) 雙雙呼叫,否則 Update 不會寫入 BLOB。WriteHuge/ReadHuge 支援 64KB 以上大檔,別用 Write/Read。CLongBinary + RFX_LongBinary 是 MFC 處理 BLOB 的標準組合,**零第三方依賴、代碼極少、穩定可靠**。掌握這套模式,Word、Excel、PDF、圖片、甚至序列化物件,統統能無縫存入資料庫。下次遇到「資料庫存檔案」需求,請自信地拿出這套方案。