在用Visual C++編寫應用程序時,常會遇到如何存取數據庫中大對象的問題。大對象文檔以二進制數據形式保存在BLOB類型的字段中,這些大對象可能是Word、Execl或圖片文件等,目前多數數據庫都支持BLOB類型的字段。
VC存取這些大對象數據有眾多方法,如OLE、ActiveX等,事實上VC的MFC提供了一個很方便的實現方法,即利用MFC提供的CLongBinary類可以方便地實現存取BLOB字段。下面筆者將舉例說明。
首先用以下SQL語句建一個含BLOB字段的數據表:
CREATE TABLE REPORTTABLE(REGISTERNUM CHAR(12) NOT NULL,REPORT BLOB(5M),PRIMARY KEY(REGISTERNUM));
建完該表後,配置好ODBC數據源,設定數據源名為ABCDB。
我們用VC的MFC AppWizard建一個新的Project,設定項目名為ABC,下一步選Single Document,在提示你想包含什麼樣的數據庫支持時,選Header files only,然後完成建立。
接著在Resources的Dailog資源中新建一個FormView,打開該FormView,啟用ClassWizard,建立一個新類,設定類名叫CReportRecordSet,Base Class選CRecordSet,然後選ABCDB為數據源,再選擇表REPORTTABLE,啟動ClassWizrd,並建立新類CReportFormView,Base Class為CRecordVIEw,選Recordset時,選CReportRecordSet。
打開ReportRecordSet.h,找到該行:CString m_REPORT; 改為CLongBinary m_REPORT;這樣程序就知道m_REPORT是和BLOB字段交換數據。同樣,我們還需要修改另外幾處,打開ReportRecordSet.cpp後,刪除m_REPORT = _T("");一句。再找到RFX_Text(pFX, _T("[REPORT]"), m_REPORT);一句,將其改為RFX_LongBinary(pFX, _T("[REPORT]"), m_REPORT); ODBC方法存取數據庫時使用RFX_LongBinary;DAO方法則用DFX_LongBinary。
再次打開FormView,添加一個Edit控件,並用ClassWizard將它和member variable m_pSet-〉m_ REGISTERNUM關聯,然後在FormVIEw上增加三個按鍵,Caption名分別叫“取得Word文檔”、“更新word文檔”、“新增word文檔”。並分別為這三個按鍵建立各自的Function,然後我們為這三個按鍵增加相應的代碼。在按鍵“取得Word文檔”的Function中加入如下代碼:
try //該程序的所在當前目錄是e:qcabc
{
if (m_pSet-〉ISEOF())
AfxMessageBox("沒有該小組的成果報告");
else
{
//下面檢測臨時文件tyj.doc是否存在
HANDLE hFind;
WIN32_FIND_DATA findData = {0};
hFind=FindFirstFile("e:qcabctyj.doc",&&findData);
// FindFirstFile是Windows API 函數
if(hFind = = INVALID_HANDLE_VALUE)
AfxMessageBox("不存在臨時文件");
else
{
AfxMessageBox("有臨時文件");
DeleteFile("e:qcabctyj.doc");
//利用API函數刪除該臨時文件
}
CString strFileName="e:qcabctyj.doc";
CFile outFile(strFileName,CFile::modeCreate|CFile::modeWrite);
//modeCreate指示構造函數創建一個新文件
//下面這段把已經在內存中的BLOB字段數據內容寫到臨時生成的文件tyj.doc中
LPSTR buffer = (LPSTR)GlobalLock(m_pSet-〉m_REPORT.m_hData);
outFile.WriteHuge(buffer,m_pSet-〉m_REPORT.m_dwDataLength);
GlobalUnlock(m_pSet-〉m_REPORT.m_hData);
outFile.Close();
ShellExecute(NULL,NULL,_T("tyj.doc"),NULL,_T("e:qcabc"),NULL);
//下面執行外部程序,Word會自動啟動並打開tyj.doc
}
}
catch(CException?pE)
{
pE-〉ReportError();
pE-〉Delete();
return;
}
在按鍵“更新Word文檔”的Function中加入以下程序代碼:
m_pSet-〉Edit(); // 聲明編輯當前記錄
UpdateData(TRUE);
CFile fileWord;
CFileStatus fileStatus;
CString fileLocate;
static char BASED_CODE szFilter[] = "Word Files (?.doc)|?.doc||";
// 下面將彈出典型的打開文件對話框,您可以選擇任何目錄下的?.doc文件
CFileDialog dlg(TRUE,NULL,NULL,0,szFilter,this);
if(dlg.DoModal()= =IDOK)
fileLocate=dlg.GetPathName();
else
fileLocate="";
if(fileLocate= ="")
AfxMessageBox("您沒選文件");
else
{
fileWord.Open(fileLocate,CFile::modeRead);
fileWord.GetStatus(fileStatus);
m_pSet-〉m_REPORT.m_dwDataLength=fileStatus.m_size;
HGLOBAL hGlobal = GlobalAlloc(GPTR,fileStatus.m_size);
m_pSet-〉m_REPORT.m_hData = GlobalLock(hGlobal);
fileWord.ReadHuge(m_pSet-〉m_REPORT.m_hData,fileStatus.m_size);
//把您選擇的文件的數據寫入m_pSet-〉m_REPORT
m_pSet-〉SetFIEldDirty(&&m_pSet-〉m_REPORT);
m_pSet-〉SetFIEldNull(&&m_pSet-〉m_REPORT,FALSE);
m_pSet-〉Update(); // 更新記錄
GlobalUnlock(hGlobal);
}
上述代碼只要稍做修改,即可把Execl等各類文件存入數據庫中。對應按鍵“新增word文檔”只需要復制“更新Word文檔”中的代碼,並把m_pSet-〉Edit();換成m_pSet-〉AddNew();即可。完成上述步驟後,打開abc.cpp,把RUNTIME_CLASS(CAbcView));這句換成RUNTIME_CLASS(CReportFormView)); 這樣程序啟動時就顯示了該FormVIEw。