图片文件是JPG、BMP等格式。
也就是想在VC中把图片文件存在SQL Server数据库中,并读出显示出来!
请问怎么解决?
用IStream流可以吗?
谢谢!

解决方案 »

  1.   

    #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
        no_namespace rename("EOF", "EndOfFile")#define ChunkSize   100#include <ole2.h>
    #include <stdio.h>
    #include "conio.h"
    #include "malloc.h"
    #include "AppendChunkX.h"//Function declarations
    inline void TESTHR(HRESULT x) {if FAILED(x) _com_issue_error(x);};
    void AppendChunkX(VOID);
    void PrintProviderError(_ConnectionPtr pConnection);///////////////////////////////////////////////////////////
    //                                                       //
    //      Main Function                                    //
    //                                                       //
    ///////////////////////////////////////////////////////////
    void main()
    {
       HRESULT  hr = S_OK;   if(FAILED(::CoInitialize(NULL)))
          return;
       
       AppendChunkX();
          
       //Wait here for the user to see the output
       printf("\n\nPress any key to continue..");
       getch();
       ::CoUninitialize();
    }
    ///////////////////////////////////////////////////////////
    //                                                       //
    //      AppendChunkX Function                            //
    //                                                       //
    ///////////////////////////////////////////////////////////
    VOID  AppendChunkX(VOID)
    {
       // Define ADO object pointers.
        // Initialize pointers on define.
        // These are in the ADODB::  namespace.
        _RecordsetPtr pRstPubInfo = NULL;
        _ConnectionPtr pConnection = NULL;
       
         //Define other variables
         IADORecordBinding   *picRs = NULL;  //Interface Pointer declared.(VC++ Extensions)   
         CPubInfoRs pubrs;          //C++ class object        HRESULT hr = S_OK;
        _bstr_t strCnn("Provider=sqloledb;Data Source=MyServer;"
             "Initial Catalog=pubs;User Id=sa;Password=;");
        
        _bstr_t strMessage,strPubID,strPRInfo;
        _variant_t varChunk;
        long lngOffSet,lngLogoSize;
         char pubId[50];
        lngOffSet = 0;    
          
        UCHAR chData;
        CHAR ch;
        SAFEARRAY FAR *psa;
        SAFEARRAYBOUND rgsabound[1];
        rgsabound[0].lLbound = 0;
        rgsabound[0].cElements = ChunkSize;    try
        {
            //Open a Connection.
            TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
            hr = pConnection->Open(strCnn,"","",adConnectUnspecified);        TESTHR(hr= pRstPubInfo.CreateInstance(__uuidof(Recordset)));          pRstPubInfo->CursorType = adOpenKeyset;
            pRstPubInfo->LockType = adLockOptimistic;        hr = pRstPubInfo->Open("pub_info",
                _variant_t((IDispatch*)pConnection,true),
                adOpenKeyset,adLockOptimistic,adCmdTable);        //Open an IADORecordBinding interface pointer which we'll use 
            //for Binding Recordset to a class    
            TESTHR(pRstPubInfo->QueryInterface(
                __uuidof(IADORecordBinding),(LPVOID*)&picRs));        //Bind the Recordset to a C++ Class here    
            TESTHR(picRs->BindToRecordset(&pubrs));        //Display the available logos here
            strMessage = "Available logos are: " + (_bstr_t)"\n\n";
            printf(strMessage);
            int Counter = 0;
            while(!(pRstPubInfo->EndOfFile))
            { 
                printf("\n%s",pubrs.m_sz_pubid);
                printf("\n%s",strtok(pubrs.m_sz_prinfo,","));            //Display 5 records at a time and wait for user to continue..
                if (++Counter >= 5)
                {
                    Counter = 0;
                    printf("\nPress any key to continue...");
                    getch();
                }
                pRstPubInfo->MoveNext(); 
            }        //Prompt For a Logo to Copy
            printf("\nEnter the ID of a logo to copy: ");
            scanf("%s",pubId);
            strPubID = pubId;        //Copy the logo to a variable in chunks        pRstPubInfo->Filter = "pub_id = '"  + strPubID + "'";
            lngLogoSize = pRstPubInfo->Fields->Item["logo"]->ActualSize;        //Create a safe array to store the array of BYTES  
            rgsabound[0].cElements = lngLogoSize;
            psa = SafeArrayCreate(VT_UI1,1,rgsabound);        long index1 = 0;
            while(lngOffSet < lngLogoSize)
            {
                varChunk = pRstPubInfo->Fields->
                            Item["logo"]->GetChunk(ChunkSize);            //Copy the data only upto the Actual Size of Field.  
                for(long index=0;index<=(ChunkSize-1);index++)
                {
                    hr= SafeArrayGetElement(varChunk.parray,&index,&chData);
                    if(SUCCEEDED(hr))
                    {
                        //Take BYTE by BYTE and advance Memory Location
                        hr = SafeArrayPutElement(psa,&index1,&chData); 
                        index1++;
                    }
                    else
                        break;
                }
                lngOffSet = lngOffSet + ChunkSize;
            }
            lngOffSet = 0;        printf("Enter a new Pub Id: ");
            scanf("%s",pubrs.m_sz_pubid);
            strPubID = pubrs.m_sz_pubid;
            printf("Enter descriptive text: " );
            scanf("%c",&ch);
            gets(pubrs.m_sz_prinfo);
            
            pRstPubInfo->AddNew();
            pRstPubInfo->Fields->GetItem("pub_id")->PutValue(strPubID);
            pRstPubInfo->Fields->GetItem("pr_info")->
                PutValue(pubrs.m_sz_prinfo);        //Assign the Safe array  to a variant. 
            varChunk.vt = VT_ARRAY|VT_UI1;
            varChunk.parray = psa;
            hr = pRstPubInfo->Fields->GetItem("logo")->
                    AppendChunk(varChunk);         //Update the table 
            pRstPubInfo->Update();        lngLogoSize = pRstPubInfo->Fields->Item["logo"]->ActualSize;        //Show the newly added record.
            printf("New Record : %s\n Description : %s\n Logo Size : %s",
                pubrs.m_sz_pubid,
                pubrs.m_sz_prinfo,(LPCSTR)(_bstr_t)pRstPubInfo->Fields->
                Item["logo"]->ActualSize);        //Delete new record because this is demonstration.
            pConnection->Execute("DELETE FROM PUB_INFO WHERE pub_id = '"
                            + strPubID +"'",NULL,adCmdText);        pRstPubInfo->Close();
            pConnection->Close();
        }    catch(_com_error &e)
       {
           // Notify the user of errors if any.
          _bstr_t bstrSource(e.Source());
          _bstr_t bstrDescription(e.Description());      PrintProviderError(pConnection);
          printf("Source : %s \n Description : %s\n",(LPCSTR)bstrSource,(LPCSTR)bstrDescription);   }
    }
    ///////////////////////////////////////////////////////////
    //                                                       //
    //      PrintProviderError Function                      //
    //                                                       //
    ///////////////////////////////////////////////////////////VOID PrintProviderError(_ConnectionPtr pConnection)
    {
       // Print Provider Errors from Connection object.
       // pErr is a record object in the Connection's Error collection.
       ErrorPtr    pErr  = NULL;
       long      nCount   = 0;    
       long      i     = 0;   if( (pConnection->Errors->Count) > 0)
       {
          nCount = pConnection->Errors->Count;
          // Collection ranges from 0 to nCount -1.
          for(i = 0; i < nCount; i++)
          {
             pErr = pConnection->Errors->GetItem(i);
             printf("\t Error number: %x\t%s", pErr->Number,(LPCSTR) pErr->Description);
          }
       }
    }
      

  2.   

    ado的 AppendChuck 和GetChunk
    来实现读取
      

  3.   

    思想就是先把二进制数据转成safearray,存入数据库,然后取出来
      

  4.   

    感谢arvid_gs(west)!
    如果不用AppendChuck 和GetChunk,还有其它办法吗?使用ado的 AppendChuck 和GetChunk感觉有点儿麻烦。
    在VC中是否可以使用stream流向数据库中存和取图象,并显示出来?
    谢谢!
      

  5.   

    stream 只能是读取
    文件成数据流,他是文件与数据流之间的操作。如果要把数据流写道数据库中的话,还得用数据库操作函数就是AppendChuck,
    这些了
      

  6.   

    其实Appendchuck 也不是很复杂,可能是我贴的太多看这个就简单一点:
    BLOB数据的保存:
    BLOB类型的数据无法用普通的方式进行存储,我们需要使用AppendChunk函数,AppendChunk包含在Field对象中,原型如下:
    HRESULT AppendChunk (const _variant_t & Data );
    从函数原型中可以看到关键的问题是我们需把二进制数据赋值给VARIANT类型的变量,下面我们给出具体的代码并作简单的分析:
    ///假设m_pBMPBuffer指针指向一块长度为m_nFileLen的二进制数据,并且已经成功打开了记录集对象m_pRecordset///char *pBuf = m_pBMPBuffer;
    VARIANT varBLOB;
    SAFEARRAY *psa;
    SAFEARRAYBOUND rgsabound[1];m_pRecordset->AddNew();                                              ///添加新记录
    m_pRecordset->PutCollect("username",_variant_t("小李"));             ///为新记录填充username字段
    m_pRecordset->PutCollect("old",_variant_t((long)28);                 ///填充old字段
    if(pBuf)
    {    
       rgsabound[0].lLbound = 0;
       rgsabound[0].cElements = m_nFileLen;
       psa = SafeArrayCreate(VT_UI1, 1, rgsabound);                      ///创建SAFEARRAY对象
       for (long i = 0; i < (long)m_nFileLen; i++)
          SafeArrayPutElement (psa, &i, pBuf++);                         ///将pBuf指向的二进制数据保存到SAFEARRAY对象psa中
       varBLOB.vt = VT_ARRAY | VT_UI1;                                   ///将varBLOB的类型设置为BYTE类型的数组
       varBLOB.parray = psa;                                             ///为varBLOB变量赋值
       m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);///加入BLOB类型的数据

    m_pRecordset->Update();                                              ///保存我们的数据到库中
    至此我们的数据已经成功地保存到了数据库中
      

  7.   

    BLOB数据的读取
    对应于保存数据时我们所使用的AppendChunk函数,读取数据应该使用GetChunk函数,GetChunk的原型如下:
    _variant_t GetChunk (long Length );
    给出数据的长度后GetChunk将返回包含数据的VARIANT类型变量,然后我们可以利用SafeArrayAccessData函数得到VARIANT变量中指向数据的char *类型的指针,以方便我们的处理,具体代码如下:long lDataSize = m_pRecordset->GetFields()->GetItem("photo")->ActualSize;///得到数据的长度
    if(lDataSize > 0)
    {
       _variant_t varBLOB;
       varBLOB = m_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);
       }
    }
      

  8.   

    谢谢arvid_gs(west)!

    http://support.microsoft.com/default.aspx?scid=kb;EN-US;258038#appliesto
    是在VB中使用stream把文件存入和读取数据库的介绍。
    由于在VC中显示图片文件时,也可以直接利用IStream和IPicture实现。所以,希望知道是否和怎样才能在VC中利用stream来实现图片文件在SQL Server数据库的存入读取以及显示操作!
    谢谢!
      

  9.   

    Ado.Stream 可以读取:下面代码可以实现读出保存在一个文件里! _StreamPtr  pStm;
    pStm.CreateInstance("ADODB.Stream");
        variant_t varOptional(DISP_E_PARAMNOTFOUND,VT_ERROR);
    pStm->PutType(adTypeBinary);
        pStm->Open( varOptional,  
                         adModeUnknown, adOpenStreamUnspecified, _bstr_t(), _bstr_t());
        pStm->Write(_variant_t(m_pRecordset->GetFields()->GetItem("photo")->Value));
        pStm->SaveToFile("c:\\publogo.bmp", adSaveCreateOverWrite);
      

  10.   

    就直接调用OleLoadPicture函数从流中装载图像
    IPicture *pPic;  
    OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic)); 
    由于该函数有时会导致失败,所以应当用SUCCEEDED宏来做一些适当的保护工作,只有在数据装载成功的前提下才能继续下面的图像显示工作: 
    if(SUCCEEDED(OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic))) 

    OLE_XSIZE_HIMETRIC hmWidth;  
    OLE_YSIZE_HIMETRIC hmHeight;  
    pPic->get_Width(&hmWidth);  
    pPic->get_Height(&hmHeight);  
    double fX,fY;  fX = (double)pDC->GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC->GetDeviceCaps(HORZSIZE)*100.0);  
    fY = (double)pDC->GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC->GetDeviceCaps(VERTSIZE)*100.0);  
    if(FAILED(pPic->Render(*pDC,0,0,(DWORD)fX,(DWORD)fY,0,hmHeight,hmWidth,-hmHeight,NULL)))  
    AfxMessageBox("图像失败!");  
    pPic->Release();  
    }  
      

  11.   

    写入数据库
    pStm->PutType(adTypeBinary);
        pStm->Open( varOptional,  
                         adModeUnknown, adOpenStreamUnspecified, _bstr_t(), _bstr_t());
        pStm->LoadFromFile("c:\\bag.gif");
    m_pRecordset->GetFields()->GetItem("photo")->Value= pStm->Read(adReadAll);
      

  12.   

    感谢arvid_gs(west) !
    非常成功!
    结帖
      

  13.   

    不过在显示时还是需要先将图片从流中保存成文件,在从文件中读入IStream中,再显示。