使用 ADO 向数据库中存储一张图片
【备注】本文中所阐述代码应用于我为BS架构业务系统开发的某个 ActiveX 控件中。
我们将向一个典型SQL数据库中的某表的 Image 类型的字段(假设字段名称为“PHOTO”)存储一副图片,实际上 Image 字段是一种二进制流,它是由应用程序负责解释的。因此在这里我们是将其当作 jpg 图像文件。换句话说,把 jpg 文件的原始字节流存储到 Image 字段中去。由于通过内存中转,这种文件的尺寸不宜过大。
我们假设在一个CImage对象中已经加载的就是要保存的图片,同时也打开了相应表的一个用于插入记录的记录集指针 (_RecordsetPtr )。
则相关代码如下:
bool SaveImage(CImage *lpImg, _RecordsetPtr pRecordset, char* errormsg)
{
//估算图像需要的内存大小,这里当作 BMP 格式来估算的,所以结果比实际需要的更大。
SIZE_T buffersize = lpImg->GetWidth() * lpImg->GetHeight() * lpImg->GetBPP()/8 + sizeof(BITMAPINFO);
HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, buffersize);
if(hMem != NULL)
{
IStream* pStream = NULL;
CreateStreamOnHGlobal(hMem, FALSE, &pStream);
if(pStream != NULL)
{
LARGE_INTEGER temp;
ULARGE_INTEGER fileLength;
temp.QuadPart = 0;
lpImg->Save(pStream); //写入内存流
//获取当前文件的位置
pStream->Seek(temp, STREAM_SEEK_CUR, &fileLength);
ULONG nLength = (ULONG)(fileLength.QuadPart+1);
SAFEARRAY* psa;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = nLength;
//VT_UI1 : Variable type is unsigned char.
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
//锁定内存
BYTE *lpBytes = (BYTE*)GlobalLock(hMem);
BYTE *lpTemp = lpBytes;
for (LONG i = 0; i < nLength; i++)
SafeArrayPutElement (psa, &i, lpTemp++);
//解锁内存
GlobalUnlock(hMem);
VARIANT varBLOB;
varBLOB.vt = VT_ARRAY | VT_UI1;
varBLOB.parray = psa;
//存储
pRecordset->Fields->GetItem("PHOTO")->AppendChunk(varBLOB);
pStream->Release();
//
SafeArrayDestroyData(psa);
}
else
{
GlobalFree(hMem);
sprintf(errormsg, "CreateStreamOnHGlobal Failed");
return false;
}
//释放全局内存
GlobalFree(hMem);
}
else
{
sprintf(errormsg, "GlobalAlloc Failed!");
return false;
}
return true;
}
下面再列举一下,如何从 image 字段中读取内容,并把它保存到一个磁盘上的普通文件。假设表具有一个自增的数字主键(“ID”)。
void ReadImg(int id)
{
_RecordsetPtr pRs = NULL;
_ConnectionPtr pConnection = NULL;
_variant_t varChunk;
HRESULT hr;
//连接字符串
_bstr_t strCnn("Provider=SQLOLEDB;Server=...;Database=...;User ID=...;Password=...;");
try
{
//Open a connection
pConnection.CreateInstance(__uuidof(Connection));
hr = pConnection->Open(strCnn,"","",NULL);
pRs.CreateInstance(__uuidof(Recordset));
//表名略
char cmdText[128];
sprintf(cmdText, "select PHOTO from ... where ID = %d", id);
pRs->Open(cmdText,_variant_t((IDispatch *) pConnection,true),adOpenKeyset,adLockOptimistic,adCmdText);
//read data
long lPhotoSize = pRs->Fields->GetItem("PHOTO")->ActualSize;
long llsRead = 0;
_variant_t varChunk;
BYTE buf[ChunkSize];
printf("lDatalength = %ld\n", lPhotoSize);
//保存到C盘
char filename[128];
sprintf(filename, "C:\\ID_%d.jpg", id);
FILE* stream = fopen(filename, "wb");
while(lPhotoSize > 0)
{
llsRead = lPhotoSize >= ChunkSize? ChunkSize:lPhotoSize;
varChunk = pRs->Fields->GetItem("PHOTO")->GetChunk(llsRead);
for(long index = 0; index < llsRead; index++)
{
SafeArrayGetElement(varChunk.parray, &index, buf+index);
}
fwrite(buf, 1, llsRead, stream);
lPhotoSize -= llsRead;
}
fclose(stream);
printf("Save File Complete: %s\n", filename);
pRs->Close();
pConnection->Close();
}
catch(_com_error &e)
{
// Notify the user of errors if any.
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
CString sError;
sError.Format(_T("Source : %s \n Description : %s\n"),(LPCSTR)bstrSource,(LPCSTR)bstrDescription);
//AfxMessageBox(sError);
//printf("%s\n", sError);
}
}
使用 ADO 向数据库中存储一张图片相关推荐
- python获取数据库用户名密码_在数据库中存储用户和密码
我正在创建一个用户+密码的软件.认证后,用户可以访问一些半公共服务,但也可以加密一些只有用户才能访问的文件.在 用户必须按原样存储,如有可能,无需修改.在auth之后,只要软件还在运行,用户和密码都会 ...
- android studio数据库存储数据,如何使用API 23在android studio中的数据库中存储数据?...
大多数时候我不会发布任何内容,因为我可以在其他帖子中找到我需要的所有内容,但是现在我已经有几天了,您如何在数据库中存储任何内容?这是我的Java代码如何使用API 23在android studi ...
- 数据库中存储日期的字段类型究竟应该用varchar还是datetime ?
背景: 前段时间在百度经验看到一篇文章<如何在电脑右下角显示你(爱人)的名字>,之前也听过这个小技巧,但没真正动手设置过.所以出于好奇就实践了一下. 设置完成后的效果例如以下.右下角的时间 ...
- 数据库中存储用户名、密码时如何处理?
一般的项目都有一个用户表,请问在这个表中,你的账号和密码都是明文存储的么?那么怎么防止被别人看见用户的密码呢? 我见过一个项目是这样的,在用户注册时就对用户的密码进行MD5加密,这样用户表中存储的密码 ...
- 数据库中存储Json格式数据
在数据库中存储Json格式数据 1.表字段类型 json 2.Java代码有两种方式: 方式一 :属性定义成String类型. 往数据库中存储的值 必须为JSON格式的字符串,因为数据库中会做一次校验 ...
- 在SQL数据库中存储纬度和经度数据时要使用的数据类型是什么? [重复]
本文翻译自:What datatype to use when storing latitude and longitude data in SQL databases? [duplicate] Th ...
- 给Double赋值为0.0时,数据库中存储为null
此分值字段为Double类型,给他赋值0.0后,数据库中依旧为null xml中的sql语句为这样. 解决方法 将sql语句修改为 即可 数据库中存储为
- 树结构如何在关系型数据库中存储
在数据库中存储分层数据 无论您是想建立自己的论坛,还是想在网站上发布邮件列表中的消息,还是想编写自己的cms:总有一天,您会希望将分层数据存储在数据库中.而且,除非您使用类似XML的数据库,否则表 ...
- 性别字段在数据库中存储数字,查询时,如何查询出数字对应的男和女?(case when的应用)
今天敲代码的时候,刚好遇到这个问题,写博客记一下. 情况如下:性别字段在数据库中存储的是数字,男对应1,女对应0.然后,查询的时候,我想查询出男和女两个字,而不是1和0. 一开始,我写的sql语句,是 ...
最新文章
- 山社电机: SAMSR -外部接口测试
- C#中使用ProtoBuf将list进行序列化并保存到文件
- JavaScript高级程序设计阅读笔记
- shiro前后端分离_为什么要前后端分离?前后端分离的优点是什么?
- 更新10_linux,时隔十年,QQ更新了Linux版本
- 5G赋能中国智慧教育
- 用shell查看关键数据
- 通过js跳转url下载包含中文的文件乱码问题解决方案(java)
- 关于TikTok的变现思考和三种玩法
- Python 2.x vs Python 3(三)
- 不依赖第三方环境和服务
- 【数据结构】可以逃课其它字符串算法的字符串哈希算法
- 数据绑定的优点_轻松应对海量数据,TiDB 在车好多的实践
- node on mac
- inception-v1 自复现 有问题尽管问
- python逻辑回归模型建模步骤_逻辑回归建模及变量重要性可视化(Python实现)
- 目标检测(四):SSD之Pytorch源码解读
- 倍福Twincat 3.0软件的EAP通讯(补充)
- 最小二乘、加权最小二乘(WLS)、迭代加权最小二乘(迭代重加全最小二乘)(IRLS)
- STM32调试诊断工具 | STM Studio介绍、下载、安装和使用教程
热门文章
- mysqli得到记录数量
- C++程序设计实践题1
- 秒杀安全狗的经验总结
- C# 6.0 的那些事
- 【DFS + 记忆化递归 + DP】LeetCode 91. Decode Ways
- 初学QT遇到的“_on_OK_clicked(bool)未定义的引用”的问题,以及使用windows远程桌面登录树莓派
- CUDA 9.0安装+CUDA版本转换 + cuDNN7.1安装
- ObjectDetecionAPI TypeError: __new__() got an unexpected keyword argument 'serialized_options'
- 一.对ThreadLocal的理解
- Linux 攻击防护基础排查