1:常用接口
個人比較喜歡sqlite, 使用最方便,唯一的准備工作是下載250K的源;而且作者很熱心,有問必答。
以下演示一下使用sqlite的步驟,先創建一個數據庫,然后查詢其中的內容。2個重要結構體和5個主要函數:
sqlite3 *pdb, 數據庫句柄,跟文件句柄FILE很類似
sqlite3_stmt *stmt, 這個相當於ODBC的Command對象,用於保存編譯好的SQL語句
sqlite3_open(), 打開數據庫
sqlite3_exec(), 執行非查詢的sql語句
sqlite3_prepare(), 准備sql語句,執行select語句或者要使用parameter bind時,用這個函數(封裝了sqlite3_exec).
Sqlite3_step(), 在調用sqlite3_prepare后,使用這個函數在記錄集中移動。
Sqlite3_close(), 關閉數據庫文件
還有一系列的函數,用於從記錄集字段中獲取數據,如
sqlite3_column_text(), 取text類型的數據。
sqlite3_column_blob(),取blob類型的數據
sqlite3_column_int(), 取int類型的數據
…
2:sqlite數據類型介紹
在進行數據庫Sql操作之前,首先有個問題需要說明,就是Sqlite的數據類型,和其他的數據庫不同,Sqlite支持的數據類型有他自己的特色,這個特色有時會被認為是一個潛在的缺點,但是這個問題並不在我們的討論范圍之內。
大多數的數據庫在數據類型上都有嚴格的限制,在建立表的時候,每一列都必須制定一個數據類型,只有符合該數據類型的數據可以被保存在這一列當中。而在 Sqlite 2.X中,數據類型這個屬性只屬於數據本生,而不和數據被存在哪一列有關,也就是說數據的類型並不受數據列限制(有一個例外:INTEGER PRIMARY KEY,該列只能存整型數據)。
但是當Sqlite進入到3.0版本的時候,這個問題似乎又有了新的答案,Sqlite的開發者開始限制這種無類型的使用,在3.0版本當中,每一列開始 擁有自己的類型,並且在數據存入該列的時候,數據庫會試圖把數據的類型向該類型轉換,然后以轉換之后的類型存儲。當然,如果轉換被認為是不可行 的,Sqlite仍然會存儲這個數據,就像他的前任版本一樣。
舉個例子,如果你企圖向一個INTEGER類型的列中插入一個字符串,Sqlite會檢查這個字符串是否有整型數據的特征, 如果有而且可以被數據庫所識別,那么該字符串會被轉換成整型再保存,如果不行,則還是作為整型存儲。
總的來說,所有存在Sqlite 3.0版本當中的數據都擁有以下之一的數據類型:
空(NULL):該值為空
整型(INTEGEER):有符號整數,按大小被存儲成1,2,3,4,6或8字節。
實數(REAL):浮點數,以8字節指數形式存儲。
文本(TEXT):字符串,以數據庫編碼方式存儲(UTF-8, UTF-16BE 或者 UTF-16-LE)。
BLOB:BLOB數據不做任何轉換,以輸入形式存儲。
ps: 在關系數據庫中,CLOB和BLOB類型被用來存放大對象。BOLB表示二進制大對象,這種數據類型通過用來保存圖片,圖象,視頻等。CLOB表示字符大對象,能夠存放大量基於字符的數據。
對應的,對於數據列,同樣有以下的數據類型:
TEXT
NUMERIC
INTEGER
REAL
NONE
數據列的屬性的作用是確定對插入的數據的轉換方向:
TEXT 將數據向文本進行轉換,對應的數據類型為NULL,TEXT 或 BLOB
NUMERIC 將數據向數字進行轉換,對應的數據類型可能為所有的五類數據,當試圖存入文本 時將執行向整型或浮點類型的轉換(視具體的數值而定),轉換若不可行,則保留文本類型存儲,NULL或BLOB不做變化
INTEGER 將數據向整型轉換,類似於NUMERIC,不同的是沒有浮點標志的浮點數將轉換為整型保存
REAL 將數據向浮點數類型轉換,類似於NUMERIC,不同的是整數將轉換為浮點數保存
NULL 不做任何轉換的數據列類型
實例代碼如下,
附件工程可直接編譯,例子使用了blob數據類型。
#include "sqlite3.h" //包含一個頭文件就可以使用所以sqlite的接口了
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#pragma comment(lib, "sqlite.lib") //我把sqlite編譯成了一個靜態的lib文件。
void createdb();
void querydb();
int main()
{
createdb();
querydb();
return 0;
}
void createdb()
{
int ret;
sqlite3 *pdb = 0;
sqlite3_stmt *stmt = 0;
char *error = 0;
char *sql = "insert into table1 values('value11',:aaa)";
int &nbs; index;
static void *value = "asdfadsfasdfjasdfjaksdfaskjdfakdsfaksfja";
ret = sqlite3_open("db1.sdb", &pdb); //打開數據庫,跟打開文本文件一樣
if( ret != SQLITE_OK )
return;
ret = sqlite3_exec(pdb, "create table table1(col1 char(20), col2 BLOB)", 0,0, &error );
if( ret != SQLITE_OK )
return;
ret = sqlite3_prepare(pdb, sql,strlen(sql), &stmt, &error);
if( ret != SQLITE_OK )
return;
index = sqlite3_bind_parameter_index(stmt, ":aaa");
ret = sqlite3_bind_blob(stmt, index, value, strlen(value), SQLITE_STATIC);
if( ret != SQLITE_OK )
return;
ret = sqlite3_step(stmt);
if( ret != SQLITE_DONE )
return;
sqlite3_close(pdb);
}
void querydb()
{
int ret;
sqlite3 *pdb = 0;
sqlite3_stmt *pstmt = 0;
char *error = 0;
char *sql = "select * from table1";
int len;
int i;
char *name;
void *value;
ret = sqlite3_open("db1.sdb", &pdb);
if( ret != SQLITE_OK )
return;
ret = sqlite3_prepare(pdb, sql, strlen(sql), &pstmt, &error);
if( ret != SQLITE_OK )
return;
while( 1 )
{
ret = sqlite3_step(pstmt);
if( ret != SQLITE_ROW )
break;
name = sqlite3_column_text(pstmt, 0);
value = sqlite3_column_blob(pstmt, 1);
len = sqlite3_column_bytes(pstmt,1 );
}
}
實例二:SQLite中如何用api操作blob類型的字段
在實際的編程開發當中我們經常要處理一些大容量二進制數據的存儲,如圖片或者音樂等等。對於這些二進制數據(blob字段)我們不能像處理普通的文本那樣 簡單的插入或者查詢,為此SQLite提供了一組函數來處理這種BLOB字段類型。下面的代碼演示了如何使用這些API函數。
首先我們要建立一個數據庫:
sqlite3_exec(db, "CREATE TABLE list (fliename varchar(128) UNIQUE, fzip blob);", 0, 0, &zErrMsg);
//由於mmmm.rar是一個二進制文件,所以要在使用insert語句時先用?號代替
sqlite3_prepare(db, "insert into list values ('mmmm.rar',?);", -1, &stat, 0);
FILE *fp;
long filesize = 0;
char * ffile;
fp = fopen("mmmm.rar", "rb");
if(fp != NULL)
{
//計算文件的大小
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
//讀取文件
ffile = new char[filesize+1];
size_t sz = fread(ffile, sizeof(char), filesize+1, fp);
fclose(fp);
}
//將文件數據綁定到insert語句中,替換“?”部分
sqlite3_bind_blob(stat, 1, ffile, filesize, NULL);
//執行綁定之后的SQL語句
sqlite3_step(stat);
這時數據庫當中已經有了一條包含BLOB字段的數據。接下來我們要讀取這條數據:
//選取該條數據
sqlite3_prepare(db, "select * from list;", -1, &stat, 0);
sqlite3_step(stat);
//得到紀錄中的BLOB字段
const void * test = sqlite3_column_blob(stat, 1);
//得到字段中數據的長度
int size = sqlite3_column_bytes(stat, 1);
//拷貝該字段
sprintf(buffer2, "%s", test);
此時可以將buffer2寫入到文件當中,至此BLOB數據處理完畢。
實例三:sqlite 中用blob存儲圖片和取出圖片
#include<iostream>
#include<string>
#include<sqlite3.h>
using namespace std;
int main()
{
sqlite3 *db;
sqlite3_stmt *stat;
char *zErrMsg = 0;
char buffer2[1024]="0";
sqlite3_open("./MetaInfo.db", &db);
int result;
if(result)
{
cout<<"Open the database sqlite.db failed"<<endl;
}
else
cout<<"Open the database sqlite.db sucessfully"<<endl;
sqlite3_exec(db, "CREATE TABLE list (fliename varchar(128) UNIQUE, fzip blob);", 0, 0, &zErrMsg);
sqlite3_prepare(db, "insert into list values ('./data/2.bmp',?);", -1, &stat, 0);
FILE *fp;
long filesize = 0;
char * ffile;
fp = fopen("./data/2.bmp", "rb");
if(fp != NULL)
{
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
ffile = new char[filesize+1];
size_t sz = fread(ffile, sizeof(char), filesize+1, fp);
fclose(fp);
}
sqlite3_bind_blob(stat, 1, ffile, filesize, NULL);
sqlite3_step(stat);
sqlite3_prepare(db, "select * from list;", -1, &stat, 0);
sqlite3_step(stat);
const void * test = sqlite3_column_blob(stat, 1);
int size = sqlite3_column_bytes(stat, 1);
sprintf(buffer2, "%s", test);
FILE *fp2;
fp2 = fopen("outfile.png", "wb");
if(fp2 != NULL)
{
size_t ret = fwrite(test, sizeof(char), size, fp2);
fclose(fp2);
}
delete(ffile);
sqlite3_finalize(stat);
sqlite3_close(db);
return 0;
}