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 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;
}