Sqlite3 操作二进制数据

前端之家收集整理的这篇文章主要介绍了Sqlite3 操作二进制数据前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


sqlite存取二进制数据

一.使用流程

要使用sqlite,需要从sqlite官网下载到三个文件,分别为sqlite3.lib,sqlite3.dll,sqlite3.h,然后再在自己的工程中配置好头文件和库文件,同时将dll文件放到当前目录下,就完成配置可以使用sqlite了。

使用的过程根据使用的函数大致分为如下几个过程:

  • sqlite3_open()
  • sqlite3_prepare()
  • sqlite3_step()
  • sqlite3_column()
  • sqlite3_finalize()
  • sqlite3_close()

这几个过程是概念上的说法,而不完全是程序运行的过程,如sqlite3_column()表示的是对查询获得一行里面的数据的列的各个操作统称,实际上在sqlite中并不存在这个函数

1.sqlite3_open():打开数据库

在操作数据库之前,首先要打开数据库。这个函数打开一个sqlite数据库文件的连接并且返回一个数据库连接对象。这个操作同时程序中的第一个调用sqlite函数,同时也是其他sqlite api的先决条件。许多的sqlite接口函数都需要一个数据库连接对象的指针作为它们的第一个参数。

函数定义

int sqlite3_open(

const char *filename,/* Database filename (UTF-8) */

sqlite3 **ppDb/* OUT: sqlite db handle */

);

int sqlite3_open16(

const void *filename,/* Database filename (UTF-16) */

int sqlite3_open_v2(

sqlite3 **ppDb,/* OUT: sqlite db handle */

int flags,/* Flags */

const char *zVfs/* Name of VFS module to use */

说明:

假如这个要被打开的数据文件不存在,则一个同名的数据库文件将被创建。如果使用sqlite3_open和sqlite3_open_v2的话,数据库将采用UTF-8的编码方式,sqlite3_open16采用UTF-16的编码方式

返回值:

如果sqlite数据库被成功打开(或创建),将会返回sqlITE_OK,否则将会返回错误码。sqlite3_errmsg()或者sqlite3_errmsg16可以用于获得数据库打开错误码的英文描述,这两个函数定义为:

const char *sqlite3_errmsg(sqlite3*);

const void *sqlite3_errmsg16(sqlite3*);

参数说明:

filename:需要被打开的数据库文件文件名,在sqlite3_open和sqlite3_open_v2中这个参数采用UTF-8编码,而在sqlite3_open16中则采用UTF-16编码

ppDb:一个数据库连接句柄被返回到这个参数,即使发生错误。唯一的一场是如果sqlite不能分配内存来存放sqlite对象,ppDb将会被返回一个NULL值。

flags:作为数据库连接的额外控制的参数,可以是sqlITE_OPEN_READONLY,sqlITE_OPEN_READWRITE和sqlITE_OPEN_READWRITE|sqlITE_OPEN_CREATE中的一个,用于控制数据库的打开方式,可以和SQLITE_OPEN_NOMUTEXSQLITE_OPEN_FULLMUTEXSQLITE_OPEN_SHAREDCACHE,以及SQLITE_OPEN_PRIVATECACHE结合使用,具体的详细情况可以查阅文档

2.sqlite3_prepare()

这个函数sql文本转换成一个准备语句(prepared statement)对象,同时返回这个对象的指针。这个接口需要一个数据库连接指针以及一个要准备的包含sql语句的文本。它实际上并不执行(evaluate)这个sql语句,它仅仅为执行准备这个sql语句

函数定义(仅列出UTF-8的)

int sqlite3_prepare(

sqlite3 *db,/* Database handle */

const char *zsql,/* sql statement,UTF-8 encoded */

int nByte,/* Maximum length of zsql in bytes. */

sqlite3_stmt **ppStmt,/* OUT: Statement handle */

const char **pzTail/* OUT: Pointer to unused portion of zsql */

int sqlite3_prepare_v2(

参数:

db:数据指针

zsqlsql语句,使用UTF-8编码

nByte:如果nByte小于0,则函数取出zsql中从开始到第一个0终止符的内容;如果nByte不是负的,那么它就是这个函数能从zsql中读取的字节数的最大值。如果nBytes非负,zsql在第一次遇见’/000/或’u000’的时候终止

pzTail:上面提到zsql在遇见终止符或者是达到设定的nByte之后结束,假如zsql还有剩余的内容,那么这些剩余的内容被存放到pZTail中,不包括终止符

ppStmt:能够使用sqlite3_step()执行的编译好的准备语句的指针,如果错误发生,它被置为NULL,如假如输入的文本不包括sql语句。调用过程必须负责在编译好的sql语句完成使用后使用sqlite3_finalize()删除它。

说明

如果执行成功,则返回sqlITE_OK,否则返回一个错误码。推荐在现在任何的程序中都使用sqlite3_prepare_v2这个函数sqlite3_prepare只是用于前向兼容

备注

<1>准备语句(prepared statement)对象

typedef struct sqlite3_stmt sqlite3_stmt;

准备语句(prepared statement)对象一个代表一个简单sql语句对象的实例,这个对象通常被称为“准备语句”或者“编译好的sql语句”或者就直接称为“语句”。

语句对象的生命周期经历这样的过程:

l使用sqlite3_prepare_v2或相关的函数创建这个对象

l使用sqlite3_bind_*()给宿主参数(host parameters)绑定值

l通过调用sqlite3_step一次或多次来执行这个sql

l使用sqlite3——reset()重置这个语句,然后回到第2步,这个过程做0次或多次

l使用sqlite3_finalize()销毁这个对象

sqlite中并没有定义sqlite3_stmt这个结构的具体内容,它只是一个抽象类型,在使用过程中一般以它的指针进行操作,而sqlite3_stmt类型的指针在实际上是一个指向Vdbe的结构体得指针

<2>宿主参数(host parameters)

在传给sqlite3_prepare_v2()的sql的语句文本或者它的变量中,满足如下模板的文字将被替换成一个参数:

l?

l?NNN,NNN代表数字

l:VVV,VVV代表字符

l@VVV

l$VVV

在上面这些模板中,NNN代表一个数字,VVV代表一个字母数字标记符(例如:222表示名称为222的标记符),sql语句中的参数(变量)通过上面的几个模板来指定,如

“select ? from ? “这个语句中指定了两个参数,sqlite语句中的第一个参数的索引值是1,这就知道这个语句中的两个参数的索引分别为1和2,使用”?”的话会被自动给予索引值,而使用”?NNN”则可以自己指定参数的索引值,它表示这个参数的索引值为NNN。”:VVV”表示一个名为”VVV”的参数,它也有一个索引值,被自动指定。

可以使用sqlite3_bind_*()来给这些参数绑定值

3.sqlite3_setp()

这个过程用于执行有前面sqlite3_prepare创建的准备语句。这个语句执行到结果的第一行可用的位置。继续前进到结果的第二行的话,只需再次调用sqlite3_setp()。继续调用sqlite3_setp()知道这个语句完成,那些不返回结果的语句(如:INSERT,UPDATE,或DELETE),sqlite3_step()只执行一次就返回

int sqlite3_step(sqlite3_stmt*);

返回值

函数的返回值基于创建sqlite3_stmt参数所使用的函数,假如是使用老版本的接口sqlite3_prepare()和sqlite3_prepare16(),返回值会是sqlITE_BUSY,sqlITE_DONE,sqlITE_ROW,sqlITE_ERROR或sqlITE_MISUSE,而v2版本的接口sqlite3_prepare_v2()和sqlite3_prepare16_v2()则会同时返回这些结果码和扩展结果码。

对所有V3.6.23.1以及其前面的所有版本,需要在sqlite3_step()之后调用sqlite3_reset(),在后续的sqlite3_ step之前。如果调用sqlite3_reset重置准备语句失败,将会导致sqlite3_ step返回sqlITE_MISUSE,但是在V3. 6.23.1以后,sqlite3_step()将会自动调用sqlite3_reset。

int sqlite3_reset(sqlite3_stmt *pStmt);

sqlite3_reset用于重置一个准备语句对象到它的初始状态,然后准备被重新执行。所有sql语句变量使用sqlite3_bind*绑定值,使用sqlite3_clear_bindings重设这些绑定。sqlite3_reset接口重置准备语句到它代码开始的时候。sqlite3_reset并不改变在准备语句上的任何绑定值,那么这里猜测,可能是语句在被执行的过程中发生了其他的改变,然后这个语句将它重置到绑定值的时候的那个状态。

4.sqlite3_column()

这个过程从执行sqlite3_step()执行一个准备语句得到的结果集的当前行中返回一个列。每次sqlite3_step得到一个结果集的列停下后,这个过程就可以被多次调用查询这个行的各列的值。对列操作是有多个函数,均以sqlite3_column为前缀

const void *sqlite3_column_blob(sqlite3_stmt*,int iCol);

int sqlite3_column_bytes(sqlite3_stmt*,35)">int sqlite3_column_bytes16(sqlite3_stmt*,35)">double sqlite3_column_double(sqlite3_stmt*,35)">int sqlite3_column_int(sqlite3_stmt*,35)">sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*,35)">const unsigned char *sqlite3_column_text(sqlite3_stmt*,35)">const void *sqlite3_column_text16(sqlite3_stmt*,35)">int sqlite3_column_type(sqlite3_stmt*,35)">sqlite3_value *sqlite3_column_value(sqlite3_stmt*,35)">第一个参数为从sqlite3_prepare返回来的prepared statement对象的指针,第二参数指定这一行中的想要被返回的列的索引。最左边的一列的索引号是0,行的列数可以使用sqlite3_colum_count()获得。

这些过程会根据情况去转换数值的类型,sqlite内部使用sqlite3_snprintf()去自动进行这个转换,下面是关于转换的细节表:

内部类型

@H_404_212@

请求的类型

@H_404_212@

转换

@H_404_212@

NULL

@H_404_212@

INTEGER

@H_404_212@

结果是0

@H_404_212@

NULL

@H_404_212@

FLOAT

@H_404_212@

结果是0.0

@H_404_212@

NULL

@H_404_212@

TEXT

@H_404_212@

结果是NULL

@H_404_212@

NULL

@H_404_212@

BLOB

@H_404_212@

结果是NULL

@H_404_212@

INTEGER

@H_404_212@

FLOAT

@H_404_212@

从整形转换到浮点型

@H_404_212@

INTEGER

@H_404_212@

TEXT

@H_404_212@

整形的ASCII码显示

@H_404_212@

INTEGER

@H_404_212@

BLOB

@H_404_212@

同上

@H_404_212@

FLOAT

@H_404_212@

INTEGER

@H_404_212@

浮点型转换到整形

@H_404_212@

FLOAT

@H_404_212@

TEXT

@H_404_212@

浮点型的ASCII显示

@H_404_212@

FLOAT

@H_404_212@

BLOB

@H_404_212@

同上

@H_404_212@

TEXT

@H_404_212@

INTEGER

@H_404_212@

使用atoi()

@H_404_212@

TEXT

@H_404_212@

FLOAT

@H_404_212@

使用atof()

@H_404_212@

TEXT

@H_404_212@

BLOB

@H_404_212@

没有转换

@H_404_212@

BLOB

@H_404_212@

INTEGER

@H_404_212@

先到TEXT,然后使用atoi

@H_404_212@

BLOB

@H_404_212@

FLOAT

@H_404_212@

先到TEXT,然后使用atof

@H_404_212@

BLOB

@H_404_212@

TEXT

@H_404_212@

如果需要的话添加0终止符

@H_404_212@

注:BLOB数据类型是指二进制的数据块,比如要在数据库中存放一张图片,这张图片就会以二进制形式存放,在sqlite中对应的数据类型就是BLOB

sqlite3_column_bytes16(sqlite3_stmt*,int iCol)两个函数返回对应列的内容的字节数,这个字节数不包括后面类型转换过程中加上的0终止符。

下面是几个最安全和最简单的使用策略

  • sqlite3_column_text(),然后sqlite3_column_bytes()
  • sqlite3_column_blob(),然后sqlite3_column_bytes()
  • sqlite3_column_text16(),然后sqlite3_column_bytes16()

5.sqlite3_finalize

int sqlite3_finalize(sqlite3_stmt *pStmt);

这个过程销毁前面被sqlite3_prepare创建的准备语句,每个准备语句都必须使用这个函数去销毁以防止内存泄露。

在空指针上调用这个函数没有什么影响,同时可以准备语句的生命周期的任一时刻调用这个函数:在语句被执行前,一次或多次调用sqlite_reset之后,或者在sqlite3_step任何调用之后不管语句是否完成执行

6.sqlite3_close

这个过程关闭前面使用sqlite3_open打开的数据库连接,任何与这个连接相关的准备语句必须在调用这个关闭函数之前被释放

二.使用举例

?
#include "stdafx.h"@H_956_502@
#include "sqlite3.h"@H_956_502@
static@H_956_502@ int@H_956_502@ callback(@H_956_502@ void@H_956_502@ *NotUsed,@H_956_502@ int@H_956_502@ argc,@H_956_502@ char@H_956_502@ **argv,@H_956_502@ char@H_956_502@ **azColName)@H_956_502@
{@H_956_502@
int@H_956_502@ i;@H_956_502@
for@H_956_502@ (i=0; i<argc; i++){@H_956_502@
printf@H_956_502@ (@H_956_502@ "%s = %s/n"@H_956_502@ ,azColName[i],argv[i] ? argv[i] : @H_956_502@ "NULL"@H_956_502@ );@H_956_502@
}@H_956_502@
printf@H_956_502@ (@H_956_502@ "/n"@H_956_502@ );@H_956_502@
return@H_956_502@ 0;@H_956_502@
}@H_956_502@
#define CHECK_RC(rc,szInfo,szErrMsg,db) if(rc!=sqlITE_OK) /@H_956_502@
{@H_956_502@ printf@H_956_502@ (@H_956_502@ "%s error!/n"@H_956_502@ ,szInfo);/@H_956_502@
printf@H_956_502@ (@H_956_502@ "%s/n"@H_956_502@ ,szErrMsg); /@H_956_502@
sqlite3_free(szErrMsg); /@H_956_502@
sqlite3_close(db); /@H_956_502@
return@H_956_502@ 0;}@H_956_502@
int@H_956_502@ _tmain(@H_956_502@ int@H_956_502@ argc,_TCHAR* argv[])@H_956_502@
{@H_956_502@
sqlite3 *db;@H_956_502@
char@H_956_502@ *dbPath=@H_956_502@ "f:/test.db"@H_956_502@ ;@H_956_502@
char@H_956_502@ *szErrMsg = 0;@H_956_502@
int@H_956_502@ rc= sqlite3_open(dbPath,&db);@H_956_502@
CHECK_RC(rc,@H_956_502@ "open database"@H_956_502@ ,db);@H_956_502@
char@H_956_502@ *szsql=@H_956_502@ "create table UserInfo(ID int primary key,UserName char,PassWord char);"@H_956_502@ ;@H_956_502@
rc=sqlite3_exec(db,szsql,&szErrMsg);@H_956_502@
CHECK_RC(rc,@H_956_502@ "create table"@H_956_502@ ,db);@H_956_502@
rc=sqlite3_exec(db,@H_956_502@ "insert into UserInfo(ID,UserName,PassWord) values(1,'kfqcome','123456')"@H_956_502@ ,@H_956_502@ "insert info"@H_956_502@ ,PassWord) values(2,'miss wang','654321')"@H_956_502@ ,db);@H_956_502@
szsql=@H_956_502@ "select * from UserInfo"@H_956_502@ ;@H_956_502@
rc = sqlite3_exec(db,callback,@H_956_502@ "query values"@H_956_502@ ,db);@H_956_502@
sqlite3_close(db);@H_956_502@
getchar@H_956_502@ ();@H_956_502@
return@H_956_502@ 0;@H_956_502@
}@H_956_502@
@H_404_212@

  输出的结果:

ID = 1

UserName = kfqcome

PassWord = 123456

ID = 2

UserName = miss wang

PassWord = 654321

这里执行sql语句用的是sqlite3_exec,它是前面几个函数的封装

int sqlite3_exec(

sqlite3*,/* An open database */

const char *sql,/* sql to be evaluated */

int (*callback)(void*,int,char**,char**),/* Callback function */

void *,/* 1st argument to callback */

char **errmsg/* Error msg written here */

sqlite3_exec是sqlite3_prepare_v2,sqlite3_step()和sqlite3_finalize()的封装,能让程序多次执行sql语句而不要写许多重复的代码

sqlite3_exec接口执行0或多个UTF-8编码的,分号分割的sql语句,传到第二个参数中。如果sqlite3_exec的第三个参数回调函数指针不为空,那么它会为每个来自执行的sql语句的结果行调用(也就是说回调函数调用多次,上面例子中会返回2个结果行,因而会被执行2次),第4个参数是传给回调函数的第一个参数,如果回调函数指针为空,那么回调不会发生同时结果行被忽略。

如果在执行sql语句中有错误发生,那么当前的语句的执行被停止,后续的语句也被跳过。第五个参数不为空的时候,它被分配内存并写入了错误信息,所以在sqlite3_exec后面需要调用sqlite3_free去释放这个对象以防止内存泄露

回调函数

第一个参数通过sqlite3_exec的第第四个参数传入的

第二个参数是结果行的列数

第三个参数是行中列数据的指针

第四个参数是行中列名称的指针


/* 程序功能: 使用sqlite的C API操作sqlite数据库,存取二进制数据. 用来测试的文件都小于65535字节,没有测试更大的文件! 参考文档: http://www.cntxk.com/Catanews/56/info8106.html 编译环境: codeblock 10.05(svn 6906) */ #include <stdio.h> #include <memory.h> #include <sqlite3.h> int main(int argc,char *argv[]) { sqlite3* pDB=NULL; char* pErrMsg; if(sqlITE_OK==sqlite3_open("./mydb.db",&pDB)) { sqlite3_exec(pDB,"create table bList(fileName varchar(16) primary key,binData blob);",NULL,&pErrMsg); { char buffer[65535]; int iLen=0; sqlite3_stmt* stmt; {//存储二进制数据 unsigned char hex[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; sqlite3_prepare(pDB,"insert into bList values ('hex',?);",-1,&stmt,NULL); sqlite3_bind_blob(stmt,hex,16,NULL); sqlite3_step(stmt); } stmt=NULL; {//存储exe文件 memset(buffer,65535); { FILE* fp=fopen(argv[0],"rb"); iLen=fread(buffer,65535,fp); fclose(fp); } sqlite3_prepare(pDB,"insert into bList values ('me.exe',buffer,iLen,NULL); sqlite3_step(stmt); } stmt=NULL; {//存储普通c文档 memset(buffer,65535); { FILE* fp=fopen("../main.c","insert into bList values ('main.txt',NULL); sqlite3_step(stmt); } stmt=NULL; {//从数据库中读取txt文件数据 char *data=NULL; memset(buffer,65535); sqlite3_prepare(pDB,"select binData from bList where fileName='main.txt';",0); sqlite3_step(stmt); data= (char *)sqlite3_column_blob(stmt,0);//得到纪录中的BLOB字段 iLen= sqlite3_column_bytes(stmt,0);//得到字段中数据的长度 memmove(buffer,data,iLen); printf("%s\n",buffer); } } sqlite3_close(pDB); } { puts("Press any key to exit..."); getchar(); } return 0; }
原文链接:https://www.f2er.com/sqlite/201245.html

猜你在找的Sqlite相关文章