• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > C++使用ADO实现存取图片的方法

C++使用ADO实现存取图片的方法

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了ado的2个常用方法,ado 个常用方法,ado,ado.net,ado.net是什么等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

一般在网上查到的资料中向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;

</div>

这些代码声明,在这个工程中使用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;
}
}

</div>

三、打开数据集,操纵数据库

在使用_RecordSetPtr对象m_pRecord时,必须先创建这种对象的一个实例:

m_pRecord.CreateInstance( __uuidof(RecordSet) );

CString strSQL;
//获取表中最大的id,下一次插入时就用id+1
strSQL.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));

</div>

上面这句一定要注意,因为上一次把一些数据放入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();

</div>

四、读取图片并存储到本地计算机

要将数据库中的二进制数据变为图片,最简单的方法就是用GDI+。GDI+有一个类是Image,可以用stream来创建对象,还可以用Save方法保存到本地,所以这个类很符合需要。

要使用GDI+,需要做些设置。首先在VS2005的项目属性中,加上gdiplus.lib。

然后在stdafx.h中添加代码

#include <GdiPlus.h>
using namespace Gdiplus;

</div>

在CApp类添加两个变量:

GdiplusStartupInput m_gdiplusstartUpInput;
ULONG_PTR m_GdiplusToken;

</div>

在CApp的InitInstance函数中添加

GdiplusStartup(&m_GdiplusToken, &m_gdiplusstartUpInput, NULL);
</div>

在ExitInstance函数中添加

GdiplusShutdown(m_GdiplusToken);
</div>

以下是读取图片数据并保存到本地的代码实现:

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

</div>

上面存储和读取数据的代码中用到了两个函数,GetEncoderClsid和SetImage2DB。它们的实现如下:
这个函数和上面的存/取函数都是一个类的成员函数,而m_pConn和m_pRecord是这个类的成员变量,所以

void CDlgTest::SetImage2DB(CString path)
{
VARIANT varChunk;
SAFEARRAY* psa;
SAFEARRAYBOUND rgsabound[1];
CFile f(path.operator LPCTSTR(),CFile::modeRead);
BYTE bval[ChunkSize+1];
long uIsRead=0;
while (1)
{
uIsRead=f.Read(bval,ChunkSize);
if (uIsRead==0) break;
rgsabound[0].cElements=uIsRead;
rgsabound[0].lLbound=0;
psa=SafeArrayCreate(VT_UI1,1,rgsabound);
for (long index=0;index<uIsRead;index++)
{
if (FAILED(SafeArrayPutElement(psa,&index,&bval[index])))
AfxMessageBox(_T("错误。"));

}
varChunk.vt =VT_ARRAY|VT_UI1;
varChunk.parray=psa;
try
{
m_pRecord->Fields->GetItem("ImageData")->AppendChunk(varChunk);
}
catch (_com_error e)
{
AfxMessageBox(_T("错误。"));
}
::VariantClear(&varChunk);
::SafeArrayDestroyData(psa);
if (uIsRead<ChunkSize)break;

}
f.Close();
}

INT CDlgTest::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++使用ADO实现存取图片的方法

相关文章

  • 2017-05-28c++制作的时间函数类
  • 2017-05-28C语言切割多层字符串(strtok_r strtok使用方法)
  • 2017-05-28C 转移表/转换表的深入分析
  • 2017-05-28C++中字符串查找操作的两则实例分享
  • 2017-05-28如何解决C语言,函数名与宏冲突
  • 2017-05-28使用C++制作简单的web服务器(续)
  • 2017-05-28C++通过COM接口操作PPT
  • 2017-05-28c语言网络编程-标准步骤(改进版)
  • 2017-05-28Qt实现图片移动实例(图文教程)
  • 2017-05-28C语言编写基于TCP和UDP协议的Socket通信程序示例

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 解析bitmap处理海量数据及其实现方法分析
    • 详谈c++11 final与override说明符
    • C语言函数的递归和调用实例分析
    • C++十六进制宏的用法详解
    • 利用C语言替换文件中某一行的方法
    • 实例讲解在C++的函数中变量参数及默认参数的使用
    • C++版本简易Flappy bird
    • 将正小数转化为2-9进制小数的实现方法
    • 文件的合并与拆分
    • C语言实现在数组A上有序合并数组B的方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有