项目在后面下载,以下是代码,有较详细的说明.
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <Windows.h>//用到了ShellExecute #include "sqlite3/sqlite3.h" /* 说明: 传给sqlite3_exec的回调函数,用来显示查询结果 对每一条查询结果调用一次该回调函数 参数: pv:由sqlite3_exec传递的初始化参数 argc:表头的列数 col:表头的名字数组指针 argv:表头的数据数组指针 返回值: 1:中断查找 0:继续列举查询到的数据 +-----------------------------------+ | id | pic | data(16进制数据) | |-----------------------------------| | 1 | a.jpg | 00 00 00 ... | |-----------------------------------| | 2 | b.jpg | XX XX XX | +-----------------------------------+ 对第一行: argc=3 即 [0]...[2] argv[0]="1",argv[1]="a.jpg",argv[2]="000000..." col[0]="id",col[1]="pic",col[2]="data" */ int callback(void* pv,int argc,char** argv,char** col) { printf("id:%s -> pic:%s\n",argv[0],argv[1]); return 0;//continue search } int main(void) { sqlite3* pDB = NULL;//先要为被打开的数据库建立一个sqlite3型的变量 sqlite3_stmt* pStmt = NULL;//sqlite3内部定义的一种"sql语句" char* szMsg = NULL;//传递给sqlite3_*,sqlite3_*为其分配内存空间装载错误消息,调用sqlite3_free释放 char buffer[1024];//我用来写sql语句等其它临时使用的缓冲区 char* file_buffer = NULL;//用来保存JPG的二进制数据 FILE* fp = NULL;//文件指针 int pic_id;//后来在显示查询时用来索引图片ID size_t file_size;//读取本地的文件的大小 或 从数据库读取的二进制数据的大小 WIN32_FIND_DATA fd;//用来查找的结构体,C库可用_finddata_t,_finfirst,_findnext HANDLE hFile = INVALID_HANDLE_VALUE;//Win32API FindFirstFile传回的句柄 int ret;//保存返回值 /*函数:sqlite3_open(char* db,sqlite3* pDB) **参数:db:数据库文件路径,都要使用UTF-8编码(或UTF-16) ** pDB:sqlite3* 型的数据库指针 **返回值:打开的状态:sqlITE_OK 成功 */ ret = sqlite3_open("./test.db",&pDB); if(ret != sqlITE_OK) { fprintf(stderr,"open error.\n"); return 1; } //sql创建表的语句,"integer primary key":主键,唯一,递增; "text":变长文本; "blob":二进制数据类型(都是变长的) _snprintf(buffer,sizeof(buffer),"create table if not exists testdb (id integer primary key,pic text,data blob);"); //执行一条语句:sqlite3_exec(sqlite3* pDB,char* sql,回调函数,初始化参数,char** ppErrMsg); //回调函数主要针对查询,这里就不需要了 if(sqlite3_exec(pDB,buffer,NULL,&szMsg) != sqlITE_OK) { fprintf(stderr,"exec error:%s\n",szMsg); sqlite3_free(szMsg);//释放内部分配的空间 sqlite3_close(pDB);//来用关闭打开的数据库 return 1; } printf("scanning pics...\n"); hFile = FindFirstFile("*.jpg",&fd);//查找所有的JPG文件 if(hFile != INVALID_HANDLE_VALUE) { do { printf("add %s...\n",fd.cFileName); //sql的插入语句:"insert into 表名 (需要的表头的名字[,...]) values (对应的值[,...]);" //对于主键不需要插入,自动会增加的; 字符串用 单引号 括起来 //对于二进制数据:可以利用sqlite3提供的准备语句完成:即使用 '?' 临时代替值(也可以使用其它符号,参考文档. 因为二进制数据太多),后面利用 sqlite3_bind_* 绑定相关的数据 //准备语句 sqlite3_prepare(sqlite3* pDB,int LenOfsql,sqlite3_stmt** ppStmt,char** pzTail) //LenOfsql可以传-1,表示到第一个'\0'为止,最后一个参数不太清楚作用,记得是指向未使用的sql,因为可以指定sql语句的长度的原因,我一般不使用 //返回sqlITE_OK表示成功 _snprintf(buffer,"insert into testdb (pic,data) values (\'%s\',?);",fd.cFileName); if(sqlite3_prepare(pDB,-1,&pStmt,NULL) != sqlITE_OK) { fprintf(stderr,"sqlite3_prepare error\n"); continue; } //C库读取文件到buffer空间 fp = fopen(fd.cFileName,"rb"); if(!fp) continue; fseek(fp,0L,SEEK_END); file_size = ftell(fp); rewind(fp); file_buffer = (char*)malloc(file_size); if(!file_buffer) { fclose(fp); continue; } fread(file_buffer,1,file_size,fp); fclose(fp); //这里就是绑定前面的'?'数据的语句,因为是data blob,所以这里使用 *_blob 函数 //sqlite3_bind_blob(sqlite3_stmt* pStmt,int which,void* pv,size_t size,XXX) //pStmt前面准备的"语句". which:第几个未设定数据的"变量"(前面的'?'),第一个是1,依次++ //返回sqlITE_OK示成功. 最后一个参数不清楚,未使用 if(sqlite3_bind_blob(pStmt,1,file_buffer,NULL)!=sqlITE_OK) { fprintf(stderr,"sqlite3_bind_blod error:%s",sqlite3_errmsg(pDB)); } //现在是真正地完成sql语句的操作:初始化语句->绑定语句->执行语句 //这里如返回sqlITE_DONE表示完成,返回值应根据语句选择. sqlITE_ROW 表示查询有了至少有了一条结果 if(sqlite3_step(pStmt) !=sqlITE_DONE) { fprintf(stderr,"sqlite3_step error:%s",sqlite3_errmsg(pDB)); } free(file_buffer); //用来析构前面的操作(准备语句)所分配的空间. 一定要析构掉,不然空间不会释放(不管是否执行成功) sqlite3_finalize(pStmt); }while(FindNextFile(hFile,&fd));//继续查找一下个 JPG 文件 printf("\n"); } else { fprintf(stderr,"no more files found\n"); sqlite3_close(pDB); return 1; } FindClose(hFile); //sql的查找语句:select 表头名[,表头名] from 表名 [order by 表头名 desc|asc]; //像查找之类的就不需要 准备->绑定->执行 这样复杂了,直接一个sqlite3_exec 就可以完成 //查询当然是需要回调的 _snprintf(buffer,"select id,pic from testdb order by id asc;"); if(sqlite3_exec(pDB,callback,"sqlite3_exec error:%s\n",szMsg); sqlite3_close(pDB); return 1; } printf("\n"); printf("Input pic's id to open(q for quit):"); while(scanf("%d",&pic_id) == 1) { _snprintf(buffer,sizeof(buffer),"select * from testdb where id=%d",pic_id); //由于是select *,且我这个表里有二进制数据,所以这里用准备语句优于直接执行语句 sqlite3_prepare(pDB,&pStmt,NULL); //sqlITE_ROW表示查询有结果 //可以使用while语句显示所有数据,直到sqlite3_step 返回 sqlITE_DONE 表示没有更多的数据为止 //我这里只有至多只有一条,因为id是唯一的 if(sqlite3_step(pStmt) == sqlITE_ROW) { //sqlite3_column_bytes 返回表头某一项的大小(字节),最左边的是0,在这里:id为0,pic是1,data是2 //pStmt,准备语句指针 file_size = sqlite3_column_bytes(pStmt,2); //left most is 0->schema:id,test,blob //sqlite3_column_text(sqlite3_stmt* pStmt,int iCol); //iCol:返回哪一项的文本(最好不要把数据类型乱用) //最左边的iCol是0,pic这里就是1,pic是text文本类型 _snprintf(buffer,"new_%s",sqlite3_column_text(pStmt,1)); //把读取到的数据保存为新文件 fp = fopen(buffer,"wb"); if(!fp) { sqlite3_finalize(pStmt); continue; } //sqlite3_column_blob 返回表头某一项的二进制数据指针,这里data是2 fwrite(sqlite3_column_blob(pStmt,2),1,fp); fclose(fp); //打开该文件 ShellExecute(NULL,"open",SW_SHOWNORMAL); } else//sqlite3_step 不是返回 sqlITE_ROW 表示没有数据 { printf("no such pic whose id is:%d\n",pic_id); } //析构掉 sqlite3_finalize(pStmt); printf("\nInput pic's id to open(q for quit):"); } //结束,关闭,退出 sqlite3_close(pDB); return 0; }