使用 ADO 向数据库中存储一张图片

简介:   【备注】本文中所阐述代码应用于我为BS架构业务系统开发的某个 ActiveX 控件中。   我们将向一个典型SQL数据库中的某表的 Image 类型的字段(假设字段名称为“PHOTO”)存储一副图片,实际上 Image 字段是一种二进制流,它是由应用程序负责解释的。

  【备注】本文中所阐述代码应用于我为BS架构业务系统开发的某个 ActiveX 控件中。

 

  我们将向一个典型SQL数据库中的某表的 Image 类型的字段(假设字段名称为“PHOTO”)存储一副图片,实际上 Image 字段是一种二进制流,它是由应用程序负责解释的。因此在这里我们是将其当作 jpg 图像文件。换句话说,把 jpg 文件的原始字节流存储到 Image 字段中去。由于通过内存中转,这种文件的尺寸不宜过大。

  我们假设在一个CImage对象中已经加载的就是要保存的图片,同时也打开了相应表的一个用于插入记录的记录集指针 (_RecordsetPtr )。

  则相关代码如下:

  

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
// 存储图片
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”)。

 

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码_ReadImage
// 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);
    }
}

 


 

 

目录
相关文章
|
1月前
|
存储 SQL Web App开发
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
SQL实践篇(一):使用WebSQL在H5中存储一个本地数据库
43 2
|
3月前
|
存储 缓存 关系型数据库
鱼和熊掌如何兼得?一文解析RDS数据库存储架构升级
阿里云RDS率先推出新型存储类型通用云盘,提供低延迟、低成本、高持久性的用户体验。
鱼和熊掌如何兼得?一文解析RDS数据库存储架构升级
|
2月前
|
存储 NoSQL MongoDB
Python爬虫之非关系型数据库存储#5
MongoDB、Redis【2月更文挑战第18天】
43 1
|
4月前
|
消息中间件 存储 缓存
写入内容丢失,各种数据库或者存储系统如何处理?
写入内容丢失,各种数据库或者存储系统如何处理?
43 0
|
3月前
|
存储 NoSQL 数据库
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
知识图谱之图数据库如何选型:知识图谱存储与图数据库总结、主流图数据库对比(JanusGraph、HugeGraph、Neo4j、Dgraph、NebulaGraph、Tugrapg)
|
2天前
|
存储 关系型数据库 MySQL
如何处理爬取到的数据,例如存储到数据库或文件中?
处理爬取的数据,可存储为txt、csv(适合表格数据)或json(适合结构化数据)文件。若需存储大量数据并执行复杂查询,可选择关系型(如MySQL)或非关系型(如MongoDB)数据库。以MySQL为例,需安装数据库和Python的pymysql库,创建数据库和表,然后编写Python代码进行数据操作。选择存储方式应考虑数据类型、数量及后续处理需求。
8 1
|
8天前
|
存储 SQL Oracle
【Oracle】玩转Oracle数据库(二):体系结构、存储结构与各类参数
【Oracle】玩转Oracle数据库(二):体系结构、存储结构与各类参数
32 7
|
16天前
|
数据库 存储 BI
SAP ABAP CDS View 源代码存储的数据库表揭秘和其他相关数据库表介绍试读版
SAP ABAP CDS View 源代码存储的数据库表揭秘和其他相关数据库表介绍试读版
10 0
SAP ABAP CDS View 源代码存储的数据库表揭秘和其他相关数据库表介绍试读版
|
26天前
|
存储 SQL 数据库
C# 将 Word 转文本存储到数据库并进行管理
C# 将 Word 转文本存储到数据库并进行管理
|
1月前
|
存储 PHP Apache
使用CFimagehost源码搭建无需数据库支持的PHP免费图片托管私人图床
使用CFimagehost源码搭建无需数据库支持的PHP免费图片托管私人图床