SQLite3 示例程序 - 表的创建/查找/二进制文件的保存

项目在后面下载,以下是代码,有较详细的说明.

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

相关文章

安装 在Windows上安装SQLite。 访问官网下载下Precompliled Binaries for Windows的两个压缩包。 创建s...
一、安装 下载地址:http://www.sqlite.org/download.html 将Precompiled Binaries for Windows下的包下...
实例: 会员信息管理 功能:1.查看数据库 2.清空数据库 3.增加会员 4.删除会员 5.更新会员 6.查找会员  ...
关于SQLite SQLite是一个轻量的、跨平台的、开源的数据库引擎,它的在读写效率、消耗总量、延迟时间和整...