数据库BLOB的存取方法(一)——AppendChunck/GetChunck
来源:互联网 发布:软件系统用户手册模板 编辑:程序博客网 时间:2024/05/08 00:28
目的是把一个文件以二进制的形式读到内存中,然后存到数据库中。本以为和平常的方法一样,作为存储过程的参数,使用Command对象进行调用。但是遇到了很多问题:
1. 二进制数据中是以字节存储的,很多特殊的字符都可能出现。比如:字符串结束符,这样CString的Format还有字符串的拷贝函数都不能用了(例如strcpy, sprintf等)。
2. 可以使用memcpy进行内存拷贝,但是由于特殊字符的存在,在知识Sql语句时还是会出错。虽然可以对特殊字符进行处理,例如将一个单引号替换成两个单引号,但是极可能出错。一个汉字是由两个字节来存储的,可能低位字节正好是一个单引号,如果替换了就会出错。
人都是被逼出来了,上网调研时,发现了BLOB的存储方法,BLOG(Binary Large Object二进制大数据对象)。下面讲述其中的一种方法:AppendChunck和GetChunck。
一、创建表
以网上常用的userinfo表为例,表有四个字段:id——用户id;username——用户名称;old——用户年龄;photo——用户照片(二进制数据)。
可以用Postgre数据库,access数据库,Sql Server2000.
二、向数据库中写二进制数据
void CFileOperDlg::OnBnClickedButtonInsertChunck()
{
// TODO: 在此添加控件通知处理程序代码
_RecordsetPtr pRecordset( __uuidof(Recordset) );
CString strSql = _T( "select * from /"userinfo/"" );
try
{
_bstr_t varSql( strSql );
// 打开记录集,这里使用普通的Select语句即可。
HRESULT hr = pRecordset->Open( varSql, m_pConnection.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText );
if ( FAILED( hr ) )
{
AfxMessageBox( _T( "打开记录集失败!" ) );
return ;
}
}
catch (_com_error & e)
{
AfxMessageBox(e.Description());
return ;
}
VARIANT varBLOB;
SAFEARRAY *psa;
SAFEARRAYBOUND rgsabound[1];
pRecordset->AddNew(); ///添加新记录
pRecordset->PutCollect("id",_variant_t(12)); // 给字段赋值
pRecordset->PutCollect("username", _variant_t( "Owen" ) );
pRecordset->PutCollect("old", _variant_t( 24 ) );
if(m_pFileBuf) // 保存文件数据的指针
{
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = m_dwFileLen; // 文件数据的长度
psa = SafeArrayCreate(VT_UI1, 1, rgsabound); ///创建SAFEARRAY对象
for (long i = 0; i < (long)m_dwFileLen; i++)
SafeArrayPutElement (psa, &i, m_pFileBuf++); ///将pBuf指向的二进制数据保存到SAFEARRAY对象psa中
varBLOB.vt = VT_ARRAY | VT_UI1; ///将varBLOB的类型设置为BYTE类型的数组
varBLOB.parray = psa; ///为varBLOB变量赋值
pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);///加入BLOB类型的数据
SafeArrayDestroyData( psa );
}
pRecordset->Update(); ///保存我们的数据到库中
pRecordset->Close();
pRecordset.Release();
}
三、从数据库中读取数据
void CFileOperDlg::OnBnClickedButtonDownloadChunck()
{
// TODO: 在此添加控件通知处理程序代码
_RecordsetPtr pRecordset( __uuidof(Recordset) );
CString strSql = _T( "select * from /"userinfo/" where id = 12" );
try
{
_bstr_t varSql( strSql );
// 打开记录集
HRESULT hr = pRecordset->Open( varSql, m_pConnection.GetInterfacePtr(), adOpenStatic, adLockOptimistic, adCmdText );
if ( FAILED( hr ) )
{
AfxMessageBox( _T( "打开记录集失败!" ) );
return ;
}
}
catch (_com_error & e)
{
AfxMessageBox(e.Description());
return ;
}
long lDataSize = pRecordset->GetFields()->GetItem("photo")->ActualSize;///得到数据的长度
if(lDataSize > 0)
{
_variant_t varBLOB;
varBLOB = pRecordset->GetFields()->GetItem("photo")->GetChunk(lDataSize);
if(varBLOB.vt == (VT_ARRAY | VT_UI1)) ///判断数据类型是否正确
{
char *pBuf = NULL;
SafeArrayAccessData(varBLOB.parray,(void **)&pBuf); ///得到指向数据的指针
/*****在这里我们可以对pBuf中的数据进行处理*****/
SafeArrayUnaccessData (varBLOB.parray);
// 将pBuf的数据保存成文件
writDataToFile( _T( "E://TestChunck.xls" ), (char*)pBuf, m_dwFileLen );
}
}
// 如果RecordSet没有关机,将其关闭
if ( pRecordset != NULL && pRecordset->GetState() == adStateOpen )
{
pRecordset->Close();
}
pRecordset.Release();
}
有一点值得注意:SafeArrayPutElement执行完毕,源Buffer就变成空了。我再释放Buffer时发现的。
- 数据库BLOB的存取方法(一)——AppendChunck/GetChunck
- 数据库BLOB的存取方法(二)——Stream方法
- Oracle数据库BLOB字段的存取
- Oracle数据库BLOB字段的存取
- Oracle数据库BLOB字段的存取
- Oracle数据库BLOB字段的存取
- Java Oracle数据库BLOB字段的存取
- 标准的hibernate存取blob和clob字段的方法
- 使用存储过程(PL/SQL)向数据库中存取BLOB对象——图片
- jdbcTemplate存取blob(图片)
- [转载]MYSQ数据库CLOB、BLOB存取
- Android SQLite 数据库 存取 BLOB 二进制 文件
- Android SQLite 数据库 存取 BLOB 二进制
- mybatis 存取Blob数据到oracle数据库
- 实现为用java访问mysql的blob—对图片进行存取
- JAVA存取CLOB和BLOB方法
- asp的对象存取数据库的方法
- 用数据库存取图片的方法
- Jquery插件(1)
- asp.net中避免操作重复提交的几种方法总结:
- 动态添加组件到flex的可折叠容器中
- Visual C++中对象的序列化与文件I/O研究
- 中科院Java高端培训视频教程第16讲-A
- 数据库BLOB的存取方法(一)——AppendChunck/GetChunck
- db2常用命令
- IT學習力
- 中科院Java高端培训视频教程第16讲-B
- 关于SqlRowSet的Invalid scale size. Cannot be less than zero异常
- Linux常用命令
- flex 制作火把等效果
- 孤独跟随
- 在写ASP网页时常用的检测代码: