zoukankan      html  css  js  c++  java
  • 使用 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”)。

    代码_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);
        }
    }


     

  • 相关阅读:
    python之名称空间
    python之对象(实例)
    python之类
    python之类和对象
    python之面向对象的程序设计
    python之函数联系
    Python之函数第三篇
    python之列表和生成器表达式篇
    网络基本概念
    Git
  • 原文地址:https://www.cnblogs.com/hoodlum1980/p/1664481.html
Copyright © 2011-2022 走看看