使用VS2008 C++模块和ADO连接ORACLE上传下载BLOB图片

1 篇文章 0 订阅
1 篇文章 0 订阅

by xjsuez

2012年4月9日

    最近做项目,使用oracle的BLOB保存大图片,将整理并测试成功的方法贴上来共享。

    本人用平台是VS2008的C++模块,如果是VC的其他平台将代码做适当修改即可。代码用ADO连接ORACLE数据库 ,数据库版本为ORACLE 10G。

   开始前,先建表,使用SQL*Plus建表:create table T_WS_PICTUREFILE(ID number(10),NAME varchar2(20),PICTURE blob;

 设置ID为主键,并使用以下红色的SQL代码进行主键自增设置

SQL>create sequence emp_sequence
  2 INCREMENT BY 1 -- 每次加几个
  3 START WITH 1--从1开始计数
  4 NOMAXVALUE-- 不设置最大值
  5 NOCYCLE-- 一直累加,不循环
  6 NOCACHE; -- 不建缓冲区

序列已创建。


SQL> create or replace trigger dectuser_tb_tri
  2 before insert on TEST
  3 for each row
  4 begin
  5 select emp_sequence.nextval into :new.ID from dual;
  6 end;
  7 /

触发器已创建

SQL> commit;

提交完成。

 

此时主键自增设置完毕,可以编代码了

stdafx.h文件中加入

#import "c:\program files\common files\system\ado\msado15.dll"no_namespacerename("EOF","adoEOF")

 

在类中添加变量

_ConnectionPtr m_pConn;

_RecordsetPtr m_pRecord;

char* m_pBMPBuffer;

 DWORD m_nFileLen;

DWORD ChunkSize;

 

在初始化函数中初始化数据库连接

     CoInitialize(NULL);                                         //初始化Com组件

     m_pConn.CreateInstance(__uuidof(Connection));           //Connection用于与数据库服务器的链接另一种方式

     /******************连接数据库********************/

     try

     {

     m_pConn->ConnectionTimeout = 5;                         //设置连接时间

     m_pConn->Open("Provider=OraOLEDB.Oracle.1;Data Source=服务名;","数据库用户名","数据库密码",adModeUnknown);//连接oracle数据库,注意此处不能用Provider=MSDAORA.1

         }

     catch(_com_errore)                                             //捕捉异常

         {

         AfxMessageBox(e.ErrorMessage());

         }

CoUninitialize();                                       //释放com组件

 

 

在上传图片的函数中写入以下代码

CString dwlSpaceTime;//用于计算程序运行时间
 DWORD dwBeginTime = ::GetTickCount(); /计算耗费时间///

 int maxid;
 maxid=GetMaxIDForBlob();

 CString strSQL;
 strSQL.Format(_T("Select * from T_WS_PICTURE where ID = %d"), maxid);
 //strSQL.Format(_T("Select ID,NAME,utl_raw.cast_to_varchar2(PICTUREFILE)  from T_WS_PICTURE where ID = %d"), maxid);
 //下面向数据库中插入图片等。
 //首先从数据库中读id最大的那条数据,主要目的是为了将RecordSet初始化
 m_pRecord.CreateInstance(__uuidof(Recordset));
 // 上面这句一定要注意,因为上一次把一些数据放入m_pRecord中,这一次再放的时候,要重新创建一次,否则数据格式要么不匹配,要么保留有上一次的数据,定位困难。
 try
  {
  m_pConn-> CursorLocation   =   adUseClient; //可能会导查询变慢
  m_pRecord->Open(_variant_t(strSQL),m_pConn.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
  }

 catch (_com_error  e)
  {
  AfxMessageBox(e.Description());
  }

 //
 CString imagename;
 char * pstrPathname;
 //CString imagepath = _T("D:/test.bmp");
 CString imagepath = _T("D:/Best.mim");
 imagename = imagepath.Right(8);
 CFile file;
 if( !file.Open( imagepath, CFile::modeRead) )
  {
  AfxMessageBox(_T("打开文件失败!"));
  return ;
  }

 m_nFileLen = file.GetLength();
 m_pBMPBuffer = new char[m_nFileLen + 1];
 if(!m_pBMPBuffer)
  {
  AfxMessageBox(_T("没有文件二进制流!"));
  return ;
  }

 if(file.Read(m_pBMPBuffer,m_nFileLen) != m_nFileLen)
  {
  AfxMessageBox(_T("读取二进制文件流失败!"));
  return ;
  }
 //


 try
  {
  m_pRecord->AddNew();      //为记录集添加新的一行,更新时就会把这条新纪录放到数据库中
  }
 catch (_com_error e)
  {
  AfxMessageBox(_T("不能插入一条新的记录!"));
  return;
  }
 try
  {

  int NewID=maxid+1;
  m_pRecord->PutCollect("ID", (_bstr_t)NewID);//使用putcollect插入非图像数据,使用SetImage2DB插入图像数据
  m_pRecord->PutCollect("NAME", (_bstr_t)imagename);

  //blob二进制流
  char     *pBuf   =   m_pBMPBuffer;
  VARIANT     varBLOB;
  SAFEARRAY   *psa;
  SAFEARRAYBOUND   rgsabound[1];
  if(pBuf)
   {        
   rgsabound[0].lLbound  =  0;
   rgsabound[0].cElements = m_nFileLen;
   psa  =  SafeArrayCreate(VT_UI1,   1,   rgsabound);                 ///创建SAFEARRAY对象
   for   (long   i   =   0;   i   <   (long)m_nFileLen;   i++)
    SafeArrayPutElement   (psa,   &i,   pBuf++);    ///将pBuf指向的二进制数据保存到SAFEARRAY对象psa中
   varBLOB.vt   =   VT_ARRAY   |   VT_UI1;  ///将varBLOB的类型设置为BYTE类型的数组
   varBLOB.parray   =   psa;   ///为varBLOB变量赋值
   m_pRecord-> GetFields()-> GetItem("PICTUREFILE")-> AppendChunk(varBLOB);///加入BLOB类型的数据
   }  
  //
  }
 catch (_com_error e)
  {
  AfxMessageBox(e.Description());
  AfxMessageBox(_T("插入图片有异常"));
  }
 m_pRecord->Update();//使用完毕,关闭m_pRecord,并设置为NULL,最后关闭数据库连接
 m_pRecord->Close();
 m_pRecord = NULL;
 delete m_pBMPBuffer;
 DWORD dwEndTime = ::GetTickCount();/计算耗费时间///
 DWORD dwSpaceTime = dwEndTime - dwBeginTime;
 dwlSpaceTime.Format( _T("上传文件完成,耗时:%u 秒"),(dwSpaceTime/1000));//显示的是秒
 AfxMessageBox(dwlSpaceTime);

 //

 

 

需要添加另外一个函数:GetMaxIDForBlob

 

int C你的类::GetMaxIDForBlob(void)
 {
 CString strSQL;
 int MaxID;
 m_pRecord.CreateInstance(__uuidof(Recordset));
 strSQL.Format(_T("Select count(*) as num, Max(ID) as maxid from T_WS_PICTURE"));
 try
  {
  m_pRecord->Open(_variant_t(strSQL),m_pConn.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
  }
 catch (_com_error e)
  {
  AfxMessageBox(_T("读取最大的id异常"));
  return 0;
  }
 //从RecordSet中获取数据数目和当前数据库中最大的ID。
 int num = m_pRecord->GetCollect("num");
 if (num != 0)
  {
  MaxID = m_pRecord->GetCollect("maxid");
  }
 else
  {
  MaxID = 0;
  }
 m_pRecord->Close();//关闭记录集
 m_pRecord.Release();//释放空间

 return MaxID;

 }

 

至此,上传BLOB文件代码完成

开始下载上传的文件

 

void C你的类::OnBnClickedDownloadFile()
 {
 // TODO: 在此添加控件通知处理程序代码
 CString dwlSpaceTime;//用于计算程序运行时间
     CString strSQL;
     strSQL.Format(_T("Select * from T_WS_PICTURE where ID = 1")); //下面向数据库中插入图片等。修改ID可以下载不同的文件
  DWORD dwBeginTime = ::GetTickCount(); /计算耗费时间///
 //首先从数据库中读id最大的那条数据,主要目的是为了将RecordSet初始化
 m_pRecord.CreateInstance(__uuidof(Recordset)); // 上面这句一定要注意,因为上一次把一些数据放入m_pRecord中,这一次再放的时候,要重新创建一次,否则数据格式要么不匹配,要么保留有上一次的数据,定位困难。
 try
  {
  m_pConn-> CursorLocation   =   adUseClient; //可能会导查询变慢
  m_pRecord->Open(_variant_t(strSQL),m_pConn.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
  }

 catch (_com_error  e)
  {
  AfxMessageBox(e.Description());
  }
 long   lDataLength = m_pRecord-> GetFields()-> GetItem( "PICTUREFILE")-> ActualSize;///得到数据的长度
 if (lDataLength>0)
  {
  _variant_t   varBLOB; 
  varBLOB=m_pRecord->GetFields()->GetItem(_variant_t("PICTUREFILE"))->GetChunk(lDataLength);     
  if(varBLOB.vt== (VT_ARRAY|VT_UI1) && varBLOB.vt!=VT_EMPTY && varBLOB.vt!=VT_NULL )               
   {
   BYTE   *pBuf   =   NULL;       
   pBuf   =   (BYTE*)GlobalAlloc(GMEM_FIXED,lDataLength); 
   SafeArrayAccessData(varBLOB.parray,(void   **)&pBuf);  
  CString strFileName = _T("E:/test.bmp");
  CFile   outFile(strFileName,CFile::modeCreate|CFile::modeWrite); //构造新文件,如果文件存在,则长度变为0
   outFile.Write(pBuf,lDataLength); 
   outFile.Close();                     
   SafeArrayUnaccessData (varBLOB.parray);                                         
   }
  }
 m_pRecord->Close();
 m_pRecord = NULL;

 DWORD dwEndTime = ::GetTickCount();/计算耗费时间///
 DWORD dwSpaceTime = dwEndTime - dwBeginTime;
 dwlSpaceTime.Format( _T("下载文件完成,耗时:%u 秒"),(dwSpaceTime/1000));//显示的是秒
 AfxMessageBox(dwlSpaceTime);
 }

 

 

 

至此,编程完成,代码经过我测试没问题。如果有小问题根据实际情况修改即可。

代码刚写好,没怎么整理,可能有点乱,高手的板砖请轻拍。

 

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值