时间:2021-05-20
一般在网上查到的资料中向Server2000存储图片代码比较多,从数据库中读取图片并显示也不少,但是把图片从数据库中二进制数据转换为原图片保存在本地,就很少有C++代码了。本文就此问题一步一步地讲一讲解决的方法:
一、使用数据库前的准备
我们使用ADO,是用_ConnectionPtr,_RecordsetPtr来操纵数据库的。还有一个_CommandPtr,本程序没有使用它。
为了使用ADO,需要导入ADO动态链接库。在工程的stdafx.h文件中,添加如下代码:
//导入ADO#import "C:\Program Files\Common Files\System\ado\msado15.dll"\rename_namespace("ADOCG")rename("EOF","EndOfFile")using namespace ADOCG;这些代码声明,在这个工程中使用ADO但不使用ADO的名字空间,并且为了避免常数冲突,将常数EOF改名为adoEOF。
再有就是要建一个简单的数据库,名字叫TestImage,里面有一个表Images,这个表有三个字段,分别是ID,Name,ImageData。
二、连接数据库
连接数据库的代码可以放入一个函数中,在想调用的地方调用。一般不推荐在CAPP类的Initalize()里连接数据库,在退出程序时关闭数据库连接。应该是在使用时连接,使用完马上关闭。项目中m_pConn是_ConnectionPtr类型的变量。
BOOL OpenConnection(){if(m_pConn == NULL){m_pConn.CreateInstance("ADODB.Connection"); //创建_ConnectionPtr的一个实例}try{if(adStateClosed == m_pConn->State) //如果已关闭{m_pConn->Open("driver={SQL Server};Server=HP-CADD722B76A0;DATABASE=TestImage;UID=sa;PWD=sa","","",adModeUnknown); //因数据库而异return true;}}catch(_com_error e){AfxMessageBox(_T("连接数据库失败!"));return false;}}三、打开数据集,操纵数据库
在使用_RecordSetPtr对象m_pRecord时,必须先创建这种对象的一个实例:
m_pRecord.CreateInstance( __uuidof(RecordSet) );CString strSQL;//获取表中最大的id,下一次插入时就用id+1strSQL.Format(_T("Select count(*) as num, Max(ID) as maxid from Images"));try{m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),adOpenDynamic, adLockUnspecified, adCmdText);}catch (_com_error e){AfxMessageBox(_T("读取最大的id异常"));eturn;}//从RecordSet中获取数据数目和当前数据库中最大的ID。int num = m_pRecord->GetCollect("num");int maxid;if (num != 0){maxid = m_pRecord->GetCollect("maxid");}else{maxid = 0;}strSQL.Format(_T("Select * from Images where ID = %d"), maxid);//下面向数据库中插入图片等。//首先从数据库中读id最大的那条数据,主要目的是为了将RecordSet初始化m_pRecord.CreateInstance(__uuidof(Recordset));上面这句一定要注意,因为上一次把一些数据放入m_pRecord中,这一次再放的时候,要重新创建一次,否则数据格式要么不匹配,要么保留有上一次的数据,定位困难。
m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText); //这是AddNew方法要求的CString imagepath = _T("F:/200713454/20090326.bmp");CString imagename = imagepath.Right(12);try{m_pRecord->AddNew(); //为记录集添加新的一行,更新时就会把这条新纪录放到数据库中}catch (_com_error e) {AfxMessageBox(_T("不能插入一条新的记录"));return;}try{//使用putcollect插入非图像数据,使用SetImage2DB插入图像数据m_pRecord->PutCollect("ID", _variant_t(maxid+1));m_pRecord->PutCollect("Name", _variant_t(imagename));SetImage2DB(imagepath);}catch (_com_error e){AfxMessageBox(_T("插入图片有异常"));return;}m_pRecord->Update();//使用完毕,关闭m_pRecord,并设置为NULL,最后关闭数据库连接m_pRecord->Close();m_pRecord = NULL;CloseConnection();四、读取图片并存储到本地计算机
要将数据库中的二进制数据变为图片,最简单的方法就是用GDI+。GDI+有一个类是Image,可以用stream来创建对象,还可以用Save方法保存到本地,所以这个类很符合需要。
要使用GDI+,需要做些设置。首先在VS2005的项目属性中,加上gdiplus.lib。
然后在stdafx.h中添加代码
#include <GdiPlus.h>using namespace Gdiplus;在CApp类添加两个变量:
GdiplusStartupInput m_gdiplusstartUpInput;ULONG_PTR m_GdiplusToken;在CApp的InitInstance函数中添加
GdiplusStartup(&m_GdiplusToken, &m_gdiplusstartUpInput, NULL);在ExitInstance函数中添加
GdiplusShutdown(m_GdiplusToken);以下是读取图片数据并保存到本地的代码实现:
OpenConnection();m_pRecord.CreateInstance(__uuidof(Recordset));CString strSQL;strSQL.Format(_T("Select * from Images where ID = 1"));try{m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),adOpenDynamic, adLockOptimistic, adCmdText);}catch (_com_error e){AfxMessageBox(_T("读取图片信息异常"));return;}LPVOID Data;char* pbuf = NULL;long lDatasize = m_pRecord->GetFields()->GetItem("ImageData")->ActualSize; //数据库中图像数据长度CString imagename = m_pRecord->GetCollect("Name").bstrVal;if (lDatasize > 0){_variant_t varBLOB;varBLOB = m_pRecord->GetFields()->GetItem("ImageData")->GetChunk(lDatasize);Data = new char[lDatasize+1];if (varBLOB.vt == (VT_ARRAY|VT_UI1)){SafeArrayAccessData(varBLOB.parray, (void **)&pbuf);memcpy(Data, pbuf, lDatasize);SafeArrayUnaccessData(varBLOB.parray);}}IStream* pStm;LONGLONG cb = lDatasize;HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);LPVOID pvData;if (hGlobal != NULL){pvData = GlobalLock(hGlobal);memcpy(pvData, Data, cb);GlobalUnlock(hGlobal);CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);}else{AfxMessageBox(_T("Error"));return;}CLSID encoderClsid;GetEncoderClsid(L"image/bmp",&encoderClsid); //确定编码格式是bmp格式Image image(pStm, TRUE);CString imagepath;imagepath.Format(_T("F:/200713454/%s"), imagename);image.Save(imagepath, &encoderClsid, NULL); //把image中的数据按照bmp编码格式存到本地m_pRecord->Close();m_pRecord = NULL;CloseConnection();上面存储和读取数据的代码中用到了两个函数,GetEncoderClsid和SetImage2DB。它们的实现如下:
这个函数和上面的存/取函数都是一个类的成员函数,而m_pConn和m_pRecord是这个类的成员变量,所以
至此就实现了存储图片和从数据库中把图片下载到本地的功能。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例讲述了C#基于SQLiteHelper类似SqlHelper类实现存取Sqlite数据库的方法。分享给大家供大家参考。具体如下:这个类不是我实现的,英文
使用C++实现对单张图片的读取和保存,C语言可以参考,比较简单。#includeusingnamespacestd;voidmain(void){//保存输入图
本文实例讲述了C++实现string存取二进制数据的方法,分享给大家供大家参考。具体方法分析如下:一般来说,STL的string很强大,用起来也感觉很舒服,这段
本文实例讲述了C++使用CriticalSection实现线程同步的方法,在前文C++线程同步实例分析的基础上增加了四行代码,使用了四个函数:EnterCrit
本文实例讲述了C#编程之事务用法。分享给大家供大家参考,具体如下:ado.net2.0的SqlTransaction使用方法/////ado.net1.0中使用