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

VC++ 存取資料庫大物件 (BLOB) 實戰:用 CLongBinary 輕鬆搞定 Word/Excel/圖片

     編輯:VC 教學

前言

資料庫裡存 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 指向此資料庫。

MFC 專案建立步驟

  1. AppWizard → Single Document → Database support: Header files only
  2. 資源視圖新增 Dialog → 右鍵 Add Class → CReportRecordSet 繼承 CRecordset → 選 DSN ABCDB → 選資料表 REPORT_TABLE
  3. 同樣建立 CReportFormView 繼承 CRecordView,關聯 CReportRecordSet

關鍵修改:將 CString 改為 CLongBinary

ReportRecordSet.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

FormView 介面佈局

  • Edit Control 綁定 m_pSet->m_REGISTER_NUM
  • 三個按鈕:取得文件、更新文件、新增文件

核心代碼實作

1. 取得文件:從 BLOB 寫入暫存檔並啟動關聯程式


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();
    }
}

2. 更新文件:從磁碟讀入 BLOB 並寫回資料庫


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("更新成功"));
}

3. 新增文件:複製更新邏輯,將 Edit() 改為 AddNew()


void CReportFormView::OnAddDocument()
{
    m_pSet->AddNew();  // 唯一差異
    // 其餘同 OnUpdateDocument
}

啟動視圖切換

在 ABC.cpp 的 InitInstance 中:


// 原:pDocTemplate->AddView(RUNTIME_CLASS(CAbcView));
pDocTemplate->AddView(RUNTIME_CLASS(CReportFormView));

避坑指南

  1. 記憶體管理:CLongBinary 內部用 GlobalAlloc,讀寫時必須 GlobalLock/Unlock,否則存取違規。
  2. 欄位標記:SetFieldDirty + SetFieldNull(..., FALSE) 雙雙呼叫,否則 Update 不會寫入 BLOB。
  3. 大檔案:WriteHuge/ReadHuge 支援 64KB 以上大檔,別用 Write/Read。
  4. Excel/圖片:只需更換檔案副檔名與過濾器,邏輯完全通用。

結語

CLongBinary + RFX_LongBinary 是 MFC 處理 BLOB 的標準組合,**零第三方依賴、代碼極少、穩定可靠**。掌握這套模式,Word、Excel、PDF、圖片、甚至序列化物件,統統能無縫存入資料庫。下次遇到「資料庫存檔案」需求,請自信地拿出這套方案。

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