最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++使用ADO實(shí)現(xiàn)存取圖片的方法

 更新時(shí)間:2014年07月25日 09:36:13   投稿:shichen2014  
這篇文章主要介紹了C++使用ADO實(shí)現(xiàn)存取圖片的方法,需要的朋友可以參考下

一般在網(wǎng)上查到的資料中向Server2000存儲圖片代碼比較多,從數(shù)據(jù)庫中讀取圖片并顯示也不少,但是把圖片從數(shù)據(jù)庫中二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為原圖片保存在本地,就很少有C++代碼了。本文就此問題一步一步地講一講解決的方法:

一、使用數(shù)據(jù)庫前的準(zhǔn)備

我們使用ADO,是用_ConnectionPtr,_RecordsetPtr來操縱數(shù)據(jù)庫的。還有一個(gè)_CommandPtr,本程序沒有使用它。

為了使用ADO,需要導(dǎo)入ADO動態(tài)鏈接庫。在工程的stdafx.h文件中,添加如下代碼:

//導(dǎo)入ADO
#import "C:\Program Files\Common Files\System\ado\msado15.dll"\
rename_namespace("ADOCG")rename("EOF","EndOfFile")
using namespace ADOCG;

這些代碼聲明,在這個(gè)工程中使用ADO但不使用ADO的名字空間,并且為了避免常數(shù)沖突,將常數(shù)EOF改名為adoEOF。

再有就是要建一個(gè)簡單的數(shù)據(jù)庫,名字叫TestImage,里面有一個(gè)表Images,這個(gè)表有三個(gè)字段,分別是ID,Name,ImageData。

二、連接數(shù)據(jù)庫

連接數(shù)據(jù)庫的代碼可以放入一個(gè)函數(shù)中,在想調(diào)用的地方調(diào)用。一般不推薦在CAPP類的Initalize()里連接數(shù)據(jù)庫,在退出程序時(shí)關(guān)閉數(shù)據(jù)庫連接。應(yīng)該是在使用時(shí)連接,使用完馬上關(guān)閉。項(xiàng)目中m_pConn是_ConnectionPtr類型的變量。

BOOL OpenConnection()
{
if(m_pConn == NULL)
{
m_pConn.CreateInstance("ADODB.Connection"); //創(chuàng)建_ConnectionPtr的一個(gè)實(shí)例
}

try
{
if(adStateClosed == m_pConn->State) //如果已關(guān)閉
{
m_pConn->Open("driver={SQL Server};Server=HP-CADD722B76A0;DATABASE=TestImage;UID=sa;PWD=sa","","",adModeUnknown); //因數(shù)據(jù)庫而異
return true;
}
}
catch(_com_error e)
{
AfxMessageBox(_T("連接數(shù)據(jù)庫失敗!"));
return false;
}
}

三、打開數(shù)據(jù)集,操縱數(shù)據(jù)庫

在使用_RecordSetPtr對象m_pRecord時(shí),必須先創(chuàng)建這種對象的一個(gè)實(shí)例:

m_pRecord.CreateInstance( __uuidof(RecordSet) );

CString strSQL;
//獲取表中最大的id,下一次插入時(shí)就用id+1
strSQL.Format(_T("Select count(*) as num, Max(ID) as maxid from Images"));
try
{
m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),
adOpenDynamic, adLockUnspecified, adCmdText);
}
catch (_com_error e)
{
AfxMessageBox(_T("讀取最大的id異常"));
eturn;
}

//從RecordSet中獲取數(shù)據(jù)數(shù)目和當(dāng)前數(shù)據(jù)庫中最大的ID。
int num = m_pRecord->GetCollect("num");
int maxid;
if (num != 0)
{
maxid = m_pRecord->GetCollect("maxid");
}
else
{
maxid = 0;
}

strSQL.Format(_T("Select * from Images where ID = %d"), maxid);
//下面向數(shù)據(jù)庫中插入圖片等。
//首先從數(shù)據(jù)庫中讀id最大的那條數(shù)據(jù),主要目的是為了將RecordSet初始化
m_pRecord.CreateInstance(__uuidof(Recordset));

上面這句一定要注意,因?yàn)樯弦淮伟岩恍?shù)據(jù)放入m_pRecord中,這一次再放的時(shí)候,要重新創(chuàng)建一次,否則數(shù)據(jù)格式要么不匹配,要么保留有上一次的數(shù)據(jù),定位困難。

m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(), 
adOpenDynamic, adLockOptimistic, adCmdText); //這是AddNew方法要求的

CString imagepath = _T("F:/200713454/20090326.bmp");
CString imagename = imagepath.Right(12);
try
{
m_pRecord->AddNew(); //為記錄集添加新的一行,更新時(shí)就會把這條新紀(jì)錄放到數(shù)據(jù)庫中
}
catch (_com_error e) 
{
AfxMessageBox(_T("不能插入一條新的記錄"));
return;
}

try
{

//使用putcollect插入非圖像數(shù)據(jù),使用SetImage2DB插入圖像數(shù)據(jù)
m_pRecord->PutCollect("ID", _variant_t(maxid+1));
m_pRecord->PutCollect("Name", _variant_t(imagename));
SetImage2DB(imagepath);
}
catch (_com_error e)
{
AfxMessageBox(_T("插入圖片有異常"));
return;
}
m_pRecord->Update();

//使用完畢,關(guān)閉m_pRecord,并設(shè)置為NULL,最后關(guān)閉數(shù)據(jù)庫連接
m_pRecord->Close();
m_pRecord = NULL;
CloseConnection();

四、讀取圖片并存儲到本地計(jì)算機(jī)

要將數(shù)據(jù)庫中的二進(jìn)制數(shù)據(jù)變?yōu)閳D片,最簡單的方法就是用GDI+。GDI+有一個(gè)類是Image,可以用stream來創(chuàng)建對象,還可以用Save方法保存到本地,所以這個(gè)類很符合需要。

要使用GDI+,需要做些設(shè)置。首先在VS2005的項(xiàng)目屬性中,加上gdiplus.lib。

然后在stdafx.h中添加代碼

#include <GdiPlus.h>
using namespace Gdiplus;

在CApp類添加兩個(gè)變量:

GdiplusStartupInput m_gdiplusstartUpInput;
ULONG_PTR m_GdiplusToken;

在CApp的InitInstance函數(shù)中添加

GdiplusStartup(&m_GdiplusToken, &m_gdiplusstartUpInput, NULL);

在ExitInstance函數(shù)中添加

GdiplusShutdown(m_GdiplusToken);

以下是讀取圖片數(shù)據(jù)并保存到本地的代碼實(shí)現(xiàn):

OpenConnection();

m_pRecord.CreateInstance(__uuidof(Recordset));
CString strSQL;
strSQL.Format(_T("Select * from Images where ID = 1"));
try
{
m_pRecord->Open(strSQL.AllocSysString(), m_pConn.GetInterfacePtr(),
adOpenDynamic, adLockOptimistic, adCmdText);
}
catch (_com_error e)
{
AfxMessageBox(_T("讀取圖片信息異常"));
return;
}

LPVOID Data;
char* pbuf = NULL;

long lDatasize = m_pRecord->GetFields()->GetItem("ImageData")->ActualSize; //數(shù)據(jù)庫中圖像數(shù)據(jù)長度
CString imagename = m_pRecord->GetCollect("Name").bstrVal;
if (lDatasize > 0)
{
_variant_t varBLOB;
varBLOB = m_pRecord->GetFields()->GetItem("ImageData")->GetChunk(lDatasize);
Data = new char[lDatasize+1];
if (varBLOB.vt == (VT_ARRAY|VT_UI1))
{
SafeArrayAccessData(varBLOB.parray, (void **)&pbuf);
memcpy(Data, pbuf, lDatasize);
SafeArrayUnaccessData(varBLOB.parray);
}
}
IStream* pStm;
LONGLONG cb = lDatasize;
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);
LPVOID pvData;
if (hGlobal != NULL)
{
pvData = GlobalLock(hGlobal);
memcpy(pvData, Data, cb);
GlobalUnlock(hGlobal);
CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
}
else
{
AfxMessageBox(_T("Error"));
return;
}

CLSID encoderClsid;
GetEncoderClsid(L"image/bmp",&encoderClsid); //確定編碼格式是bmp格式
Image image(pStm, TRUE);
CString imagepath;
imagepath.Format(_T("F:/200713454/%s"), imagename);
image.Save(imagepath, &encoderClsid, NULL); //把image中的數(shù)據(jù)按照bmp編碼格式存到本地

m_pRecord->Close();
m_pRecord = NULL;
CloseConnection();

上面存儲和讀取數(shù)據(jù)的代碼中用到了兩個(gè)函數(shù),GetEncoderClsid和SetImage2DB。它們的實(shí)現(xiàn)如下:
這個(gè)函數(shù)和上面的存/取函數(shù)都是一個(gè)類的成員函數(shù),而m_pConn和m_pRecord是這個(gè)類的成員變量,所以

void CDlgTest::SetImage2DB(CString path)
{
VARIANT varChunk;
SAFEARRAY* psa;
SAFEARRAYBOUND rgsabound[1];
CFile f(path.operator LPCTSTR(),CFile::modeRead);
BYTE bval[ChunkSize+1];
long uIsRead=0;
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);
for (long index=0;index<uIsRead;index++)
{
if (FAILED(SafeArrayPutElement(psa,&index,&bval[index])))
AfxMessageBox(_T("錯誤。"));

}
varChunk.vt =VT_ARRAY|VT_UI1;
varChunk.parray=psa;
try
{
m_pRecord->Fields->GetItem("ImageData")->AppendChunk(varChunk);
}
catch (_com_error e)
{
AfxMessageBox(_T("錯誤。"));
}
::VariantClear(&varChunk);
::SafeArrayDestroyData(psa);
if (uIsRead<ChunkSize)break;

}
f.Close();
}

INT CDlgTest::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure

GetImageEncoders(num, size, pImageCodecInfo);

for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
} 
}

free(pImageCodecInfo);
return -1; // Failure
}

至此就實(shí)現(xiàn)了存儲圖片和從數(shù)據(jù)庫中把圖片下載到本地的功能。

相關(guān)文章

  • 關(guān)于c語言的一個(gè)小bug詳解

    關(guān)于c語言的一個(gè)小bug詳解

    以下是對c語言中的一個(gè)小bug進(jìn)行了詳細(xì)的分析介紹。需要的朋友可以過來參考下
    2013-08-08
  • C++中智能指針最常用的shared_ptr和unique_ptr

    C++中智能指針最常用的shared_ptr和unique_ptr

    C++中的智能指針最常用的是shared_ptr和unique_ptr,C++新手最常問的問題是我從一個(gè)函數(shù)中拿到unique_ptr,但要轉(zhuǎn)成shared_ptr才能使用,要怎么轉(zhuǎn)換?同理是否能將shared_ptr轉(zhuǎn)換成unique_ptr,面對這些問題,跟隨小編一起看看吧
    2022-08-08
  • 深入解讀C++ 內(nèi)聯(lián)函數(shù)inline|nullptr

    深入解讀C++ 內(nèi)聯(lián)函數(shù)inline|nullptr

    內(nèi)聯(lián)函數(shù):用** inline 修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會在調(diào)用的地方展開內(nèi)聯(lián)函數(shù)**,這樣調(diào)用內(nèi)聯(lián)函數(shù)就需要創(chuàng)建棧楨,就提高效率了,這篇文章給大家介紹C++ 內(nèi)聯(lián)函數(shù)inline|nullptr的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • C++中雙冒號::用法案例詳解

    C++中雙冒號::用法案例詳解

    這篇文章主要介紹了C++中雙冒號::用法案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • 詳解C語言數(shù)組靈活多變的訪問形式

    詳解C語言數(shù)組靈活多變的訪問形式

    這篇文章主要介紹了詳解C語言數(shù)組靈活多變的訪問形式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 深入全排列算法及其實(shí)現(xiàn)方法

    深入全排列算法及其實(shí)現(xiàn)方法

    本篇文章是對全排列算法及其實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 一文帶你了解C語言中的0長度數(shù)組(可變數(shù)組/柔性數(shù)組)

    一文帶你了解C語言中的0長度數(shù)組(可變數(shù)組/柔性數(shù)組)

    眾所周知,?GNU/GCC?在標(biāo)準(zhǔn)的?C/C++?基礎(chǔ)上做了有實(shí)用性的擴(kuò)展,?零長度數(shù)組(Arrays?of?Length?Zero)?就是其中一個(gè)知名的擴(kuò)展,本文就來聊聊零長度數(shù)組的相關(guān)知識吧
    2023-03-03
  • C語言基礎(chǔ)知識點(diǎn)解析(extern,static,typedef,const)

    C語言基礎(chǔ)知識點(diǎn)解析(extern,static,typedef,const)

    本篇文章是對C語言基礎(chǔ)知識點(diǎn)(extern,static,typedef,const)的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-10-10
  • C語言實(shí)現(xiàn)順序表的插入刪除

    C語言實(shí)現(xiàn)順序表的插入刪除

    這篇文章主要介紹了C語言實(shí)現(xiàn)順序表的插入刪除,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • C++ override關(guān)鍵字使用詳解

    C++ override關(guān)鍵字使用詳解

    這篇文章主要介紹了C++ override關(guān)鍵字使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01

最新評論

昌宁县| 辰溪县| 乌拉特前旗| 苏尼特左旗| 达拉特旗| 方正县| 陵水| 新余市| 绍兴市| 岚皋县| 金沙县| 衡南县| 乌拉特前旗| 新蔡县| 萨嘎县| 岳阳市| 米脂县| 乐安县| 武清区| 乐昌市| 台南市| 霍邱县| 保靖县| 宕昌县| 滦南县| 台山市| 峨眉山市| 桐乡市| 闽侯县| 奉贤区| 高青县| 昆山市| 邵阳市| 怀集县| 卢氏县| 阳西县| 禹州市| 三门县| 双江| 乡城县| 罗甸县|