VC应该如何读取Oracle的Clob字段?

xxxuuujjj 2009-08-13 09:27:11
我用SQLGetData来获取字段的内容时,只能读到1000多个字节。
应该用什么API来得到该类型字段的内容呢??
...全文
326 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
bohut 2009-08-13
  • 打赏
  • 举报
回复
在用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:\qc\abc\

  { if (m_pSet-〉IsEOF())

  AfxMessageBox("没有该小组的成果报告");

  else {//下面检测临时文件tyj.doc是否存在

  HANDLE hFind;

  WIN32_FIND_DATA findData = {0};

  hFind=FindFirstFile("e:\\qc\\abc\\tyj.doc",&&findData);

  // FindFirstFile是Windows API 函数

  if(hFind = = INVALID_HANDLE_VALUE)

  AfxMessageBox("不存在临时文件");

  else

  {AfxMessageBox("有临时文件");

  DeleteFile("e:\\qc\\abc\\tyj.doc");

  //利用API函数删除该临时文件

  }

  CString strFileName="e:\\qc\\abc\\tyj.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:\\qc\\abc\\"),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。

  以上所有代码均在IBM UDB6、Visual C++ 6.0、Windows 98环境下编译通过。
xxxuuujjj 2009-08-13
  • 打赏
  • 举报
回复
谢谢!
但我的整个工程是用ODBC连接数据库的,要是改成ADO连接会很麻烦。
在不改变该结构的情况下有没有好方法呢?
bohut 2009-08-13
  • 打赏
  • 举报
回复
用ado连接oracle

读取大数据量字段:
long lSize = m_pRecordset->Fields->Item["data"]->ActualSize; //data是你的Clob字段
while(lSize>0)
{
 lIsRead= lSize >=ChunkSize?ChunkSize:lSize;
 //从字段data中获取一个数据包
 varChunk = m_pRecordset->Fields->Item["data"]->GetChunk(lIsRead);
 for(index=0;index<LISREAD;INDEX++)
  ::SafeArrayGetElement(varChunk.parray,&index,buf+index);
  //将数据包写入文件
  f.Write(buf,lIsRead);
  lSize -=lIsRead;
}

4,011

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 数据库
社区管理员
  • 数据库
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧