关于用ODBC操作ACCESS写BLOB字段(OLE对象)的问题!

DDGG 2009-08-14 06:10:07
VC6写的一个MFC对话框应用程序,一个ACCESS数据库(.MDB),数据库中有一张表Table1,表有2个字段,数据结构如下:

字段名称  数据类型
Id     文本
Data    OLE 对象

问题来了:如何使用ODBC的方式将二进制数据写入Data字段?

在网上找了好久都没找到一篇文章说清楚了的!
只知道要使用CLongBinary,好像还要继承CRecordset创建新类(这个没弄明白)
望有经验的朋友能写个简单的示例,非常感谢!

我的打开数据库的代码:

CDatabase db;
std::string strDsn;

strDsn = "ODBC;DRIVER={MICROSOFT ACCESS DRIVER (*.mdb)};DBQ=C:/Test.mdb";
db.Open(NULL, FALSE, FALSE, strDsn.c_str());


我拟设的写ACCESS表的代码:

char sBuffer[65536] = {0};
CRecordset rs(&db);
rs.Open(CRecordset::forwardOnly, "Table1", CRecordset::appendOnly);
rs.AddNew();
. // 这里该怎么写??
. // 假设要把sBuffer里的64K数据写入Data字段里吧。
. // 拜托了!
rs.Update()
rs.Close()
...全文
412 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
DDGG 2010-04-22
  • 打赏
  • 举报
回复
呵呵,我最后还是只能用ADO做了,没办法啊
zhang02001 2010-04-22
  • 打赏
  • 举报
回复
我真是服了,不懂的和不懂装懂的别乱回答好不,吃饱撑的了?
DDGG 2009-08-17
  • 打赏
  • 举报
回复
搞什么嘛,我的问题写得那么明确,可回答问题的人却总是在打转球。。
MoXiaoRab 2009-08-17
  • 打赏
  • 举报
回复
貌似稍微修改下就行了吧?
jcwinner 2009-08-17
  • 打赏
  • 举报
回复
ado方便,干吗不用ado呢?
DDGG 2009-08-17
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 tr0j4n 的回复:]
1、SafeArray:

在对BLOB进行操作时,要用到SAFEARRAY结构。SAFEARRAY是一种结构化的数据类型,包含了一个由其它数据类型的数据元素组成的数组。 之所以称之为安全的数组是因为它包含了每一维的边界信息,并限制在边界内进行数组元素的访问。其Win32定义SAFEARRAY如下:

typedef struct tagSAFEARRAY
{
unsigned short cDims;
unsigned short fFeatures;
unsigned long cbElements;
unsigned long cLocks;
void * pvData;
SAFEARRAYBOUND rgsabound[ 1 ];
} SAFEARRAY;

这个结构的成员(cDims,cLocks等)是通过API函数来设置和管理的。真正的数据存放在pvData成员中,而SAFEARRAYBOUND结构定义该数组结构的细节。以下就是该结构成员的简要描述:

成员 描述
cDims 数组的维数
fFeatures 用来描述数组如何分配和如何被释放的标志
cbElements 数组元素的大小
cLocks 一个计数器,用来跟踪该数组被锁定的次数
pvData 指向数据缓冲的指针
rgsabound 描述数组每维的数组结构,其大小是可变的

rgsabound是一个有趣的成员,它的结构不太直观。它是数据范围的数组。该数组的大小依safe array维数的不同而有所区别。rgsabound成员是一个SAFEARRAYBOUND结构的数组--每个元素代表SAFEARRAY的一个维。

typedef struct tagSAFEARRAYBOUND
{
unsigned long cElements;
unsigned long lLbound;
} SAFEARRAYBOUND;

维数被定义在cDims成员中。例如,一个'C'类数组的维数可以是[3][4][5]-一个三维的数组。如果我们使用一个SAFEARRAY来表示这 个结构,我们定义一个有三个元素的rgsabound数组--一个代表一维。cDims = 3; SAFEARRAYBOUND rgsabound[ 3 ]; rgsabound[0]元素定义第一维。在这个例子中ILBOUND元素为0,是数组的下界。cElements成员的值等于三。数组的第二维 ([4])可以被rgsabound结构的第二个元素定义。下界也可以是0,元素的个数是4,第三维也是这样。
[/Quote]

tr0j4n 老兄给点貌似是ADO的方法。。ODBC哪来的AppendChunk啊?
DDGG 2009-08-17
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bohut 的回复:]
http://bbs.voc.com.cn/topic-18103-1-1.html
[/Quote]

这个是讲的文档窗体吧?大哥!
我的是对话框项目哦,我能在项目里添加ID为IDD_FORMVIEW的对话框资源,但是为对话框创建类的时候基类列表里却没有CRecordSet可选。
MoXiaoRab 2009-08-16
  • 打赏
  • 举报
回复
2、将二进制文件写入到数据库:

由于这个二进制文件可能很大,所以无法将所有内容一次性读入到内存。我们需要多次读入,每次可 以使用函数CFile::Read()从文件中读出一个数据包,然后调用Field对象的AppandChrnk()函数将该包读入数据库。 AppandChrnk()函数包含在Field对象中,原型如下:HRESULT AppendChunk (const _variant_t & Data );从函数原型中可以看到关键的问题是我们需把二进制数据赋值给VARIANT类型的变量。实现的关键代码如下:

CFile f;
...打开文件
//

SAFEARRAY * psa=NULL;
#define CHUNKSIZE 200
BYTE bVal[CHUNKSIZE];
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); ///创建SAFEARRAY对象

for(long index=0;index<UISREAD;INDEX++)
SafeArrayPutElement(psa,&index,&bVal[index]);

VARIANT varChunk;
varChunk.vt = VT_ARRAY|VT_UI1;
varChunk.parray = psa;
//加入BLOB类型的数据
m_pRecordset->Fields->GetItem("data")->AppendChunk(varChunk);
::VariantClear(&varChunk);
::SafeArrayDestroyData( psa);

if(uIsRead<CHUNKSIZE) break;
}

我们所有的读入数据工作都在一个while循环中实现,每次读入一个数据包,直到读完这个数据,即数据量为二进制数据的长度ChunkSize。其中 *pBuf为指向缓冲区指针,即要读入的数据包。ChunkSize为VARIANT变量,用于保存二进制数据,psa是指向安全数组SAFEARRAY 的指针。

3、从数据库读出二进制对象到文件:

同样,由于这个二进制对象可能很大,无法将所有内容一次性读入内存中对应于保存数据时我们所使用的AppendChunk函数,读取数据应该使用GetChunk函数,GetChunk的原型如下:

_variant_t GetChunk (long Length );唯一的参数Length代表需要读取的字节数。

实现的关键代码如下:

long lBlobSize = m_pRecordset->Fields-> Item["data"] ->ActualSize;
while(lBlobSize>0)
{
lIsRead= lBlobSize >=ChunkSize? ChunkSize: lBlobSize;
//从字段data中获取一个数据包
varChunk = m_pRecordset->Fields->Item["data"]->GetChunk(lIsRead);
for(index=0;index<LISREAD;INDEX++)
::SafeArrayGetElement(varChunk.parray,&index,buf+index);
//将数据包写入文件
f.Write(buf,lIsRead);
lBlobSize -=lIsRead;
}

其中f是一个CFile对象,代表了要存储的文件。Long型变量lBlobSize记录了二进制对象的大小。利用一个while循环,每次从数据库中读取lIsRead字节,直至将其全部读出。
MoXiaoRab 2009-08-16
  • 打赏
  • 举报
回复
1、SafeArray:

在对BLOB进行操作时,要用到SAFEARRAY结构。SAFEARRAY是一种结构化的数据类型,包含了一个由其它数据类型的数据元素组成的数组。 之所以称之为安全的数组是因为它包含了每一维的边界信息,并限制在边界内进行数组元素的访问。其Win32定义SAFEARRAY如下:

typedef struct tagSAFEARRAY
{
unsigned short cDims;
unsigned short fFeatures;
unsigned long cbElements;
unsigned long cLocks;
void * pvData;
SAFEARRAYBOUND rgsabound[ 1 ];
} SAFEARRAY;

这个结构的成员(cDims,cLocks等)是通过API函数来设置和管理的。真正的数据存放在pvData成员中,而SAFEARRAYBOUND结构定义该数组结构的细节。以下就是该结构成员的简要描述:

成员 描述
cDims 数组的维数
fFeatures 用来描述数组如何分配和如何被释放的标志
cbElements 数组元素的大小
cLocks 一个计数器,用来跟踪该数组被锁定的次数
pvData 指向数据缓冲的指针
rgsabound 描述数组每维的数组结构,其大小是可变的

rgsabound是一个有趣的成员,它的结构不太直观。它是数据范围的数组。该数组的大小依safe array维数的不同而有所区别。rgsabound成员是一个SAFEARRAYBOUND结构的数组--每个元素代表SAFEARRAY的一个维。

typedef struct tagSAFEARRAYBOUND
{
unsigned long cElements;
unsigned long lLbound;
} SAFEARRAYBOUND;

维数被定义在cDims成员中。例如,一个'C'类数组的维数可以是[3][4][5]-一个三维的数组。如果我们使用一个SAFEARRAY来表示这 个结构,我们定义一个有三个元素的rgsabound数组--一个代表一维。cDims = 3; SAFEARRAYBOUND rgsabound[ 3 ]; rgsabound[0]元素定义第一维。在这个例子中ILBOUND元素为0,是数组的下界。cElements成员的值等于三。数组的第二维 ([4])可以被rgsabound结构的第二个元素定义。下界也可以是0,元素的个数是4,第三维也是这样。
bohut 2009-08-14
  • 打赏
  • 举报
回复
http://bbs.voc.com.cn/topic-18103-1-1.html
DDGG 2009-08-14
  • 打赏
  • 举报
回复
楼上讲的太高深了。。我只想要一段简单的示例。
jameshooo 2009-08-14
  • 打赏
  • 举报
回复
OLE的数据组织方式完全由你自己定义,除非它也要被其它软件使用,就必须使用复合文档的模式保存,但原理都是一致的。
一个OLE对象要支持持久化,就必须实现 IPersistStream[Init]/IPersistStorage/IPersistPropertyBag中的至少一个接口,你可以向对象的这些接口发出保存指令,让它把数据写到你提供的数据接口上(IStream/IStorage/IPropertyBag),然后从这些接口中得到数据保存到你的CLongBinary变量中

4,011

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 数据库
社区管理员
  • 数据库
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧