日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

基于sqlite数据库的C语言编程

發(fā)布時(shí)間:2023/12/18 数据库 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于sqlite数据库的C语言编程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一 SQLITE 操作入門(mén)
sqlite 提供的是一些 C 函數(shù)接口,你可以用這些函數(shù)操作數(shù)據(jù)庫(kù)。通過(guò)使用這些接口,傳遞一些標(biāo)準(zhǔn) sql 語(yǔ)句(以 char * 類型)給 sqlite 函數(shù), sqlite 就會(huì)為你操作數(shù)據(jù)庫(kù)。
sqlite 跟 MS 的 access 一樣是文件型數(shù)據(jù)庫(kù),就是說(shuō),一個(gè)數(shù)據(jù)庫(kù)就是一個(gè)文件,此數(shù)據(jù)庫(kù)里可以建立很多的表,可以建立索引、觸發(fā)器等等,但是,它實(shí)際上得到的就是一個(gè)文件。備份這個(gè)文件就備份了整個(gè)數(shù)據(jù)庫(kù)。
sqlite 不需要任何數(shù)據(jù)庫(kù)引擎,這意味著如果你需要 sqlite 來(lái)保存一些用戶數(shù)據(jù),甚至都不需要安裝數(shù)據(jù)庫(kù) ( 如果你做個(gè)小軟件還要求人家必須裝了 sqlserver 才能運(yùn)行,那也太黑心了 ) 。
下面開(kāi)始介紹數(shù)據(jù)庫(kù)基本操作。
1 基本流程
( 1 )關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
sqlite 里最常用到的是 sqlite3 * 類型。從數(shù)據(jù)庫(kù)打開(kāi)開(kāi)始, sqlite 就要為這個(gè)類型準(zhǔn)備好內(nèi)存,直到數(shù)據(jù)庫(kù)關(guān)閉,整個(gè)過(guò)程都需要用到這個(gè)類型。當(dāng)數(shù)據(jù)庫(kù)打開(kāi)時(shí)開(kāi)始,這個(gè)類型的變量就代表了你要操作的數(shù)據(jù)庫(kù)。下面再詳細(xì)介紹。
( 2 )打開(kāi)數(shù)據(jù)庫(kù)
int sqlite3_open( 文件名 , sqlite3 ** );
用這個(gè)函數(shù)開(kāi)始數(shù)據(jù)庫(kù)操作。
需要傳入兩個(gè)參數(shù),一是數(shù)據(jù)庫(kù)文件名,比如: c:\\DongChunGuang_Database.db 。
文件名不需要一定存在,如果此文件不存在, sqlite 會(huì)自動(dòng)建立它。如果它存在,就嘗試把它當(dāng)數(shù)據(jù)庫(kù)文件來(lái)打開(kāi)。
sqlite3 ** 參數(shù)即前面提到的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)。這個(gè)結(jié)構(gòu)底層細(xì)節(jié)如何,你不要關(guān)它。
函數(shù)返回值表示操作是否正確,如果是 SQLITE_OK 則表示操作正常。相關(guān)的返回值 sqlite 定義了一些宏。具體這些宏的含義可以參考 sqlite3.h 文件。里面有詳細(xì)定義(順便說(shuō)一下, sqlite3 的代碼注釋率自稱是非常高的,實(shí)際上也的確很高。只要你會(huì)看英文, sqlite 可以讓你學(xué)到不少東西)。
下面介紹關(guān)閉數(shù)據(jù)庫(kù)后,再給一段參考代碼。
( 3 ) 關(guān)閉數(shù)據(jù)庫(kù)
int sqlite3_close(sqlite3 *);
前面如果用 sqlite3_open 開(kāi)啟了一個(gè)數(shù)據(jù)庫(kù),結(jié)尾時(shí)不要忘了用這個(gè)函數(shù)關(guān)閉數(shù)據(jù)庫(kù)。
下面給段簡(jiǎn)單的代碼:
extern "C"
#include "./sqlite3.h"
};
int main( int , char** )
sqlite3 * db = NULL; // 聲明sqlite 關(guān)鍵結(jié)構(gòu)指針
int result;
// 打開(kāi)數(shù)據(jù)庫(kù)
// 需要傳入 db 這個(gè)指針的指針,因?yàn)?sqlite3_open 函數(shù)要為這個(gè)指針?lè)峙鋬?nèi)存,還要讓db 指針指向這個(gè)內(nèi)存區(qū)
result = sqlite3_open( “ c:\\Dcg_database.db ” , &db );
if( result != SQLITE_OK )
{
// 數(shù)據(jù)庫(kù)打開(kāi)失敗
return -1;
// 數(shù)據(jù)庫(kù)操作代碼
// …
// 數(shù)據(jù)庫(kù)打開(kāi)成功
// 關(guān)閉數(shù)據(jù)庫(kù)
sqlite3_close( db );
return 0;
這就是一次數(shù)據(jù)庫(kù)操作過(guò)程。
二 SQL 語(yǔ)句操作
在sqlite下有一些命令和在mysql下是不一樣的,例如很多命令式以點(diǎn)好開(kāi)頭的,用 .help 可以查看。
但是標(biāo)準(zhǔn)的SQL語(yǔ)法sqlite是支持的。
( 1 )執(zhí)行 sql 語(yǔ)句
int sqlite3_exec(sqlite3*, const char *sql, sqlite3_callback, void *, char **errmsg );
這就是執(zhí)行一條 sql 語(yǔ)句的函數(shù)。
第 1 個(gè)參數(shù)不再說(shuō)了,是前面 open 函數(shù)得到的指針。說(shuō)了是關(guān)鍵數(shù)據(jù)結(jié)構(gòu)。
第 2 個(gè)參數(shù) const char *sql 是一條 sql 語(yǔ)句,以 \0 結(jié)尾。
第 3 個(gè)參數(shù) sqlite3_callback 是回調(diào),當(dāng)這條語(yǔ)句執(zhí)行之后, sqlite3 會(huì)去調(diào)用你提供的這個(gè)函數(shù)。(什么是回調(diào)函數(shù),自己找別的資料學(xué)習(xí))
第 4 個(gè)參數(shù) void * 是你所提供的指針,你可以傳遞任何一個(gè)指針參數(shù)到這里,這個(gè)參數(shù)最終會(huì)傳到回調(diào)函數(shù)里面,如果不需要傳遞指針給回調(diào)函數(shù),可以填 NULL 。等下我們?cè)倏椿卣{(diào)函數(shù)的寫(xiě)法,以及這個(gè)參數(shù)的使用。
第 5 個(gè)參數(shù) char ** errmsg 是錯(cuò)誤信息。注意是指針的指針。 sqlite3 里面有很多固定的錯(cuò)誤信息。執(zhí)行 sqlite3_exec 之后,執(zhí)行失敗時(shí)可以查閱這個(gè)指針(直接 printf( “ %s\n ” ,errmsg) )得到一串字符串信息,這串信息告訴你錯(cuò)在什么地方。 sqlite3_exec 函數(shù)通過(guò)修改你傳入的指針的指針,把你提供的指針指向錯(cuò)誤提示信息,這樣 sqlite3_exec 函數(shù)外面就可以通過(guò)這個(gè) char* 得到具體錯(cuò)誤提示。
說(shuō)明:通常, sqlite3_callback 和它后面的 void * 這兩個(gè)位置都可以填 NULL 。填 NULL 表示你不需要回調(diào)。比如你做 insert 操作,做 delete 操作,就沒(méi)有必要使用回調(diào)。而當(dāng)你做 select 時(shí),就要使用回調(diào),因?yàn)?sqlite3 把數(shù)據(jù)查出來(lái),得通過(guò)回調(diào)告訴你查出了什么數(shù)據(jù)。
( 2 ) exec 的回調(diào)
typedef int (*sqlite3_callback)( void *, int , char **, char **);
你的回調(diào)函數(shù)必須定義成上面這個(gè)函數(shù)的類型。下面給個(gè)簡(jiǎn)單的例子:
//sqlite3 的回調(diào)函數(shù)
// sqlite 每查到一條記錄,就調(diào)用一次這個(gè)回調(diào)
int LoadMyInfo( void * para, int n_column, char ** column_value, char ** column_name )
//para 是你在 sqlite3_exec 里傳入的 void * 參數(shù)
// 通過(guò)para 參數(shù),你可以傳入一些特殊的指針(比如類指針、結(jié)構(gòu)指針),然后在這里面強(qiáng)制轉(zhuǎn)換成對(duì)應(yīng)的類型(這里面是void* 類型,必須強(qiáng)制轉(zhuǎn)換成你的類型才可用)。然后操作這些數(shù)據(jù)
//n_column 是這一條記錄有多少個(gè)字段 ( 即這條記錄有多少列)
// char ** column_value 是個(gè)關(guān)鍵值,查出來(lái)的數(shù)據(jù)都保存在這里,它實(shí)際上是個(gè)1 維數(shù)組(不要以為是2 維數(shù)組),每一個(gè)元素都是一個(gè) char * 值,是一個(gè)字段內(nèi)容(用字符串來(lái)表示,以\0 結(jié)尾)
//char ** column_name 跟 column_value 是對(duì)應(yīng)的,表示這個(gè)字段的字段名稱
// 這里,我不使用 para 參數(shù)。忽略它的存在.
int i;
printf( “ 記錄包含 %d 個(gè)字段\n ” , n_column );
for( i = 0 ; i < n_column; i ++ )
printf( “ 字段名:%s ? > 字段值:%s\n ” , column_name[i], column_value[i] );
printf( “ ------------------\n “ );
return 0;
int main( int , char ** )
sqlite3 * db;
int result;
char * errmsg = NULL;
result = sqlite3_open( “ c:\\Dcg_database.db ” , &db );
if( result != SQLITE_OK )
{
// 數(shù)據(jù)庫(kù)打開(kāi)失敗
return -1;
// 數(shù)據(jù)庫(kù)操作代碼
// 創(chuàng)建一個(gè)測(cè)試表,表名叫 MyTable_1 ,有2 個(gè)字段: ID 和 name 。其中ID 是一個(gè)自動(dòng)增加的類型,以后insert 時(shí)可以不去指定這個(gè)字段,它會(huì)自己從0 開(kāi)始增加
result = sqlite3_exec( db, “ create table MyTable_1( ID integer primary key autoincrement, name nvarchar(32) ) ” , NULL, NULL, errmsg );
if(result != SQLITE_OK )
printf( “ 創(chuàng)建表失敗,錯(cuò)誤碼:%d ,錯(cuò)誤原因:%s\n ” , result, errmsg );
// 插入一些記錄
result = sqlite3_exec( db, “ insert into MyTable_1( name ) values ( ‘ 走路 ’ ) ” , 0, 0, errmsg );
if(result != SQLITE_OK )
printf( “ 插入記錄失敗,錯(cuò)誤碼:%d ,錯(cuò)誤原因:%s\n ” , result, errmsg );
result = sqlite3_exec( db, “ insert into MyTable_1( name ) values ( ‘ 騎單車(chē) ’ ) ” , 0, 0, errmsg );
if(result != SQLITE_OK )
printf( “ 插入記錄失敗,錯(cuò)誤碼:%d ,錯(cuò)誤原因:%s\n ” , result, errmsg );
result = sqlite3_exec( db, “ insert into MyTable_1( name ) values ( ‘ 坐汽車(chē) ’ ) ” , 0, 0, errmsg );
if(result != SQLITE_OK )
printf( “ 插入記錄失敗,錯(cuò)誤碼:%d ,錯(cuò)誤原因:%s\n ” , result, errmsg );
// 開(kāi)始查詢數(shù)據(jù)庫(kù)
result = sqlite3_exec( db, “ select * from MyTable_1 ” , LoadMyInfo, NULL, errmsg );
// 關(guān)閉數(shù)據(jù)庫(kù)
sqlite3_close( db );
return 0;
通 過(guò)上面的例子,應(yīng)該可以知道如何打開(kāi)一個(gè)數(shù)據(jù)庫(kù),如何做數(shù)據(jù)庫(kù)基本操作。
有這些 知識(shí),基本上可以應(yīng)付很多數(shù)據(jù)庫(kù)操作了。
( 3 )不使用回調(diào)查詢數(shù)據(jù)庫(kù)
上面介紹的 sqlite3_exec 是使用回調(diào)來(lái)執(zhí)行 select 操作。還有一個(gè)方法可以直接查詢而不需要回調(diào)。但是,我個(gè)人感覺(jué)還是回調(diào)好,因?yàn)榇a可以更加整齊,只不過(guò)用回調(diào)很麻煩,你得聲明一個(gè)函數(shù),如果這個(gè)函數(shù)是類成員函數(shù),你還不得不把它聲明成 static 的(要問(wèn)為什么?這又是 C++ 基礎(chǔ)了。 C++ 成員函數(shù)實(shí)際上隱藏了一個(gè)參數(shù): this , C++ 調(diào)用類的成員函數(shù)的時(shí)候,隱含把類指針當(dāng)成函數(shù)的第一個(gè)參數(shù)傳遞進(jìn)去。結(jié)果,這造成跟前面說(shuō)的 sqlite 回調(diào)函數(shù)的參數(shù)不相符。只有當(dāng)把成員函數(shù)聲明成 static 時(shí),它才沒(méi)有多余的隱含的 this 參數(shù))。
雖然回調(diào)顯得代碼整齊,但有時(shí)候你還是想要非回調(diào)的 select 查詢。這可以通過(guò) sqlite3_get_table 函數(shù)做到。
int sqlite3_get_table(sqlite3*, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg );
第 1 個(gè)參數(shù)不再多說(shuō),看前面的例子。
第 2 個(gè)參數(shù)是 sql 語(yǔ)句,跟 sqlite3_exec 里的 sql 是一樣的。是一個(gè)很普通的以 \0 結(jié)尾的 char * 字符串。
第 3 個(gè)參數(shù)是查詢結(jié)果,它依然一維數(shù)組(不要以為是二維數(shù)組,更不要以為是三維數(shù)組)。它內(nèi)存布局是:第一行是字段名稱,后面是緊接著是每個(gè)字段的值。下面用例子來(lái)說(shuō)事。
第 4 個(gè)參數(shù)是查詢出多少條記錄(即查出多少行)。
第 5 個(gè)參數(shù)是多少個(gè)字段(多少列)。
第 6 個(gè)參數(shù)是錯(cuò)誤信息,跟前面一樣,這里不多說(shuō)了。
下面給個(gè)簡(jiǎn)單例子 :
int main( int , char ** )
sqlite3 * db;
int result;
char * errmsg = NULL;
char **dbResult; // 是 char ** 類型,兩個(gè)* 號(hào)
int nRow, nColumn;
int i , j;
int index;
result = sqlite3_open ( “ c:\\Dcg_database.db ” , &db );
if( result != SQLITE_OK )
{
// 數(shù)據(jù)庫(kù)打開(kāi)失敗
return -1;
}
// 數(shù)據(jù)庫(kù)操作代碼
// 假設(shè)前面已經(jīng)創(chuàng)建了 MyTable_1 表
// 開(kāi)始查詢,傳入的 dbResult 已經(jīng)是 char ** ,這里又加了一個(gè) & 取地址符,傳遞進(jìn)去的就成了 char ***
result = sqlite3_get_table ( db, “ select * from MyTable_1 ” , &dbResult, &nRow, &nColumn, &errmsg );
if( SQLITE_OK == result )
{
// 查詢成功
index = nColumn; // 前面說(shuō)過(guò) dbResult 前面第一行數(shù)據(jù)是字段名稱,從 nColumn 索引開(kāi)始才是真正的數(shù)據(jù)
printf( “ 查到%d 條記錄\n ” , nRow );
for( i = 0; i < nRow ; i++ )
{
printf( “ 第 %d 條記錄\n ” , i+1 );
for( j = 0 ; j < nColumn; j++ )
{
printf( “ 字段名:%s ? > 字段值:%s\n ” , dbResult[j], dbResult [index] );
++index; // dbResult 的字段值是連續(xù)的,從第0 索引到第 nColumn - 1 索引都是字段名稱,從第 nColumn 索引開(kāi)始,后面都是字段值,它把一個(gè)二維的表(傳統(tǒng)的行列表示法)用一個(gè)扁平的形式來(lái)表示
}
printf( “ -------\n ” );
}
}
// 到這里,不論數(shù)據(jù)庫(kù)查詢是否成功,都釋放 char** 查詢結(jié)果,使用 sqlite 提供的功能來(lái)釋放
sqlite3_free_table ( dbResult );
// 關(guān)閉數(shù)據(jù)庫(kù)
sqlite3_close ( db );
return 0;
到這個(gè)例子為止, sqlite3 的常用用法都介紹完了。
用以上的方法,再配上 sql 語(yǔ)句,完全可以應(yīng)付絕大多數(shù)數(shù)據(jù)庫(kù)需求。
但有一種情況,用上面方法是無(wú)法實(shí)現(xiàn)的:需要 insert 、 select 二進(jìn)制。當(dāng)需要處理二進(jìn)制數(shù)據(jù)時(shí),上面的方法就沒(méi)辦法做到。
三 操作二進(jìn)制
我自己編了一個(gè)fruit的程序,將水果圖片插入數(shù)據(jù)庫(kù),然后讀出,當(dāng)然還是一個(gè)水果。(這里沒(méi)有給出)
sqlite 操作二進(jìn)制數(shù)據(jù)需要用一個(gè)輔助的數(shù)據(jù)類型: sqlite3_stmt * 。
這個(gè)數(shù)據(jù)類型記錄了一個(gè)“ sql 語(yǔ)句”。為什么我把 “ sql 語(yǔ)句” 用雙引號(hào)引起來(lái)?因?yàn)槟憧梢园?sqlite3_stmt * 所表示的內(nèi)容看成是 sql 語(yǔ)句,但是實(shí)際上它不是我們所熟知的 sql 語(yǔ)句。它是一個(gè)已經(jīng)把 sql 語(yǔ)句解析了的、用 sqlite 自己標(biāo)記記錄的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
正因?yàn)檫@個(gè)結(jié)構(gòu)已經(jīng)被解析了,所以你可以往這個(gè)語(yǔ)句里插入二進(jìn)制數(shù)據(jù)。當(dāng)然,把二進(jìn)制數(shù)據(jù)插到 sqlite3_stmt 結(jié)構(gòu)里可不能直接 memcpy ,也不能像 std::string 那樣用 + 號(hào)。必須用 sqlite 提供的函數(shù)來(lái)插入。
( 1 )寫(xiě)入二進(jìn)制
下面說(shuō)寫(xiě)二進(jìn)制的步驟。
要插入二進(jìn)制,前提是這個(gè)表的字段的類型是 blob 類型。我假設(shè)有這么一張表:
create table Tbl_2( ID integer, file_content blob )
首先聲明
sqlite3_stmt * stat;
然后 ,把一個(gè) sql 語(yǔ)句解析到 stat 結(jié)構(gòu)里去:
sqlite3_prepare ( db, “ insert into Tbl_2( ID, file_content) values( 10, ? ) ” , -1, &stat, 0 );
上 面的函數(shù)完成 sql 語(yǔ)句的解析。第一個(gè)參數(shù)跟前面一樣,是個(gè) sqlite3 * 類型變量,第二個(gè)參數(shù)是一個(gè) sql 語(yǔ)句。
這個(gè) sql 語(yǔ)句特別之處在于 values 里面有個(gè) ? 號(hào)。在 sqlite3_prepare 函數(shù)里, ? 號(hào)表示一個(gè)未定的值,它的值等下才插入。
第三個(gè)參數(shù)我寫(xiě)的是 -1 ,這個(gè)參數(shù)含義是前面 sql 語(yǔ)句的長(zhǎng)度。如果小于 0 , sqlite 會(huì)自動(dòng)計(jì)算它的長(zhǎng)度(把 sql 語(yǔ)句當(dāng)成以 \0 結(jié)尾的字符串)。
第四個(gè)參數(shù)是 sqlite3_stmt 的指針的指針。解析以后的 sql 語(yǔ)句就放在這個(gè)結(jié)構(gòu)里。
第五個(gè)參數(shù)我也不知道是干什么的。為 0 就可以了。
如果這個(gè)函數(shù)執(zhí)行成功(返回值是 SQLITE_OK 且 stat 不為 NULL ),那么下面就可以開(kāi)始插入二進(jìn)制數(shù)據(jù) 。
sqlite3_bind_blob ( stat, 1, pdata, ( int )(length_of_data_in_bytes), NULL ); // pdata 為數(shù)據(jù)緩沖區(qū),length_of_data_in_bytes 為數(shù)據(jù)大小,以字節(jié)為單位
這個(gè)函數(shù)一共有 5 個(gè)參數(shù)。
第 1 個(gè)參數(shù):是前面 prepare 得到的 sqlite3_stmt * 類型變量。
第 2 個(gè)參數(shù): ? 號(hào)的索引。前面 prepare 的 sql 語(yǔ)句里有一個(gè) ? 號(hào),假如有多個(gè) ? 號(hào)怎么插入?方法就是改變 bind_blob 函數(shù)第 2 個(gè)參數(shù)。這個(gè)參數(shù)我寫(xiě) 1 ,表示這里插入的值要替換 stat 的第一個(gè) ? 號(hào)(這里的索引從 1 開(kāi)始計(jì)數(shù),而非從 0 開(kāi)始)。如果你有多個(gè) ? 號(hào),就寫(xiě)多個(gè) bind_blob 語(yǔ)句,并改變它們的第 2 個(gè)參數(shù)就替換到不同的 ? 號(hào)。如果有 ? 號(hào)沒(méi)有替換, sqlite 為它取值 null 。
第 3 個(gè)參數(shù):二進(jìn)制數(shù)據(jù)起始指針。
第 4 個(gè)參數(shù):二進(jìn)制數(shù)據(jù)的長(zhǎng)度,以字節(jié)為單位。
第 5 個(gè)參數(shù):是個(gè)析夠回調(diào)函數(shù),告訴 sqlite 當(dāng)把數(shù)據(jù)處理完后調(diào)用此函數(shù)來(lái)析夠你的數(shù)據(jù)。這個(gè)參數(shù)我還沒(méi)有使用過(guò),因此理解也不深刻。但是一般都填 NULL ,需要釋放的內(nèi)存自己用代碼來(lái)釋放。
bind 完了之后,二進(jìn)制數(shù)據(jù)就進(jìn)入了你的“ sql 語(yǔ)句”里了。你現(xiàn)在可以把它保存到數(shù)據(jù)庫(kù)里:
int result = sqlite3_step ( stat );
通過(guò)這個(gè)語(yǔ) 句, stat 表示的 sql 語(yǔ)句就被寫(xiě)到了數(shù)據(jù)庫(kù)里。
最后,要把 sqlite3_stmt 結(jié) 構(gòu)給釋放:
sqlite3_finalize ( stat ); // 把剛才分配的內(nèi)容析構(gòu)掉
( 2 )讀出二進(jìn)制
下面說(shuō)讀二進(jìn)制的步驟 。
跟前面一樣 ,先聲明 sqlite3_stmt * 類型變量:
sqlite3_stmt * stat;
然后, 把一個(gè) sql 語(yǔ)句解析到 stat 結(jié)構(gòu)里去:
sqlite3_prepare ( db, “ select * from Tbl_2 ” , -1, &stat, 0 );
當(dāng) prepare 成功之后(返回值是 SQLITE_OK ),開(kāi)始查詢數(shù)據(jù)。
int result = sqlite3_step ( stat );
這一句的返回值是 SQLITE_ROW 時(shí)表示成功(不是 SQLITE_OK )。
你可以循環(huán)執(zhí)行 sqlite3_step 函數(shù),一次step 查詢出一條記錄。直到返回值不為 SQLITE_ROW 時(shí)表示查詢結(jié)束。
然后開(kāi)始獲取第一個(gè)字段 :ID 的值。ID 是個(gè)整數(shù),用下面這個(gè)語(yǔ)句獲取它的值:
int id = sqlite3_column_int( stat, 0 ); // 第2 個(gè)參數(shù)表示獲取第幾個(gè)字段內(nèi)容,從0 開(kāi)始計(jì)算,因?yàn)槲业谋淼腎D 字段是第一個(gè)字段,因此這里我填0
下面開(kāi)始獲取 file_content 的值,因?yàn)?file_content 是二進(jìn)制,因此我需要得到它的指針,還有它的長(zhǎng)度:
const void * pFileContent = sqlite3_column_blob ( stat, 1 );
int len = sqlite3_column_bytes ( stat, 1 );
這樣就得到了二進(jìn)制的值 。
把 pFileContent 的內(nèi)容保存出來(lái)之后,不要忘了釋放 sqlite3_stmt 結(jié)構(gòu):
sqlite3_finalize ( stat ); // 把剛才分配的內(nèi)容析構(gòu)掉
( 3 )重復(fù)使用 sqlite3_stmt 結(jié)構(gòu)
如果你需要重復(fù)使用 sqlite3_prepare 解析好的 sqlite3_stmt 結(jié)構(gòu),需要用函數(shù): sqlite3_reset 。
result = sqlite3_reset (stat);
這樣, stat 結(jié)構(gòu)又成為 sqlite3_prepare 完成時(shí)的狀態(tài),你可以重新為它 bind 內(nèi)容。
4 事務(wù)處理
sqlite 是支持事務(wù)處理的。如果你知道你要同步刪除很多數(shù)據(jù),不仿把它們做成一個(gè)統(tǒng)一的事務(wù)。
通常一 次 sqlite3_exec 就是一次事務(wù),如果你要?jiǎng)h除 1 萬(wàn)條數(shù)據(jù), sqlite 就做了 1 萬(wàn)次:開(kāi)始新事務(wù) -> 刪除一條數(shù)據(jù) -> 提交事務(wù) -> 開(kāi)始新事務(wù) -> … 的過(guò)程。這個(gè)操作是很慢的。因?yàn)闀r(shí)間都花在了開(kāi)始事務(wù)、提交事務(wù)上。
你可以把這些同類操作做成一個(gè)事務(wù),這樣如果操作錯(cuò)誤,還能夠回滾事務(wù)。
事務(wù)的操作沒(méi)有特別的接口函數(shù),它就是一個(gè)普通的 sql 語(yǔ)句而已:
分別如下 :
int result;
result = sqlite3_exec ( db, "begin transaction", 0, 0, &zErrorMsg ); // 開(kāi)始一個(gè)事務(wù)
result = sqlite3_exec ( db, "commit transaction", 0, 0, &zErrorMsg ); // 提交事務(wù)
result = sqlite3_exec ( db, "rollback transaction", 0, 0, &zErrorMsg ); // 回滾事務(wù)
關(guān)于代碼,可以參照下面一片文章,我已經(jīng)在這個(gè)基礎(chǔ)上編寫(xiě)了一個(gè)程序,有一個(gè)問(wèn)題是,我們用fseek和ftell求文件的長(zhǎng)度之后,要記得用SEEK_SET將位置指針設(shè)置為文件的開(kāi)始處,粗心的同學(xué)不要忘了這個(gè)。代碼轉(zhuǎn)自于這里
1.首先包含相關(guān)頭文件:
#include "sqlite3.h"
#pragma comment(lib,"sqlite3.lib")
2.創(chuàng)建數(shù)據(jù)庫(kù):
sqlite3 * db;
sqlite3_stmt *stat;
char *zErrMsg=0;
sqlite3_open("F:\\C++\\sqlite\\Bin.db",&db);
if(db==NULL)
{
return;
}
sqlite3_exec(db,"create table image (filename varchar(128) unique,img blob);",0,0,&zErrMsg);
sqlite3_close(db);
3.將圖片插入數(shù)據(jù)庫(kù):
sqlite3 * db;
sqlite3_stmt *stat;
char *zErrMsg=0;
FILE *fp=NULL;
long filesize=0;
char* ffile=NULL;
char* buf=NULL;
sqlite3_open("F:\\C++\\sqlite\\Bin.db",&db);
if(db==NULL)
{
return;
}
fp=fopen("F:\\C++\\sqlite\\131.jpg","rb");
if(fp!=NULL)
{
fseek(fp,0,SEEK_END);
filesize=ftell(fp);
fseek(fp,0,SEEK_SET);
ffile=new char[filesize];
size_t sz=fread(ffile,sizeof(char),filesize,fp);
fclose(fp);
}
//sqlite3_exec(db,"create table image (filename varchar(128) unique,img blob);",0,0,&zErrMsg);
sqlite3_prepare(db,"insert into image values ('girl.jpg',?)",-1,&stat,0);
sqlite3_bind_blob(stat,1,ffile,filesize,NULL);
sqlite3_step(stat);
delete[] ffile;
sqlite3_finalize(stat);
sqlite3_close(db);
4.導(dǎo)出圖片:
sqlite3 * db;
sqlite3_stmt *stat2;
char *zErrMsg=0;
long filesize=0;
int rc;
char* buf=NULL;
sqlite3_open("F:\\C++\\sqlite\\Bin.db",&db);
if(db==NULL)
{
return;
}
sqlite3_prepare(db,"select * from image",-1,&stat2,0);
sqlite3_step(stat2);
//while (rc == SQLITE_ROW)
FILE *fp2;
fp2=fopen("F:\\C++\\sqlite\\Show.jpg","wb");
const void *ImgData=sqlite3_column_blob(stat2,1);
int size=sqlite3_column_bytes(stat2,1);
size_t ret=fwrite(ImgData,sizeof(char),size,fp2);
fclose(fp2);
sqlite3_finalize(stat2);
sqlite3_close(db);
5.更新圖片:
sqlite3 * db;
sqlite3_stmt *stat;
char *zErrMsg=0;
FILE *fp=NULL;
long filesize=0;
char* ffile=NULL;
char* buf=NULL;
sqlite3_open("F:\\C++\\sqlite\\Bin.db",&db);
if(db==NULL)
{
return;
}
fp=fopen("F:\\C++\\sqlite\\124.jpg","rb");
if(fp!=NULL)
{
fseek(fp,0,SEEK_END);
filesize=ftell(fp);
fseek(fp,0,SEEK_SET);
ffile=new char[filesize];
size_t sz=fread(ffile,sizeof(char),filesize,fp);
fclose(fp);
}
sqlite3_prepare(db,"update image set img=? where filename='girl.jpg'",-1,&stat,0);
sqlite3_bind_blob(stat,1,ffile,filesize,NULL);
sqlite3_step(stat);
delete[] ffile;
sqlite3_finalize(stat);
sqlite3_close(db);

轉(zhuǎn)載于:https://www.cnblogs.com/elect-fans/archive/2012/08/04/2622475.html

總結(jié)

以上是生活随笔為你收集整理的基于sqlite数据库的C语言编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。