zoukankan      html  css  js  c++  java
  • C/C++语言操作sqlite数据库(增删改查)

    在某项目中,需要在前端相机中做人脸比对,因此需要在前端相机中增加一个人脸底库,人脸底库由uuid和人脸特征值组成。其中特征值为512个float数据,移植sqlite用来保存底库信息,首先写了一个demo,验证可行性之后应用到实际项目中

        sqlite3 * db= NULL;
        int rc = 0;
        char * sql = new char[800];//这个要适当的申请大一点,要不然不够用。
        char * zErrMsg = NULL;
    
        string id1 = "aaa";//用来模拟32位的uuid.
        std::vector<float> feature1{0.12, 0.23, 0.34, 0.45, 0.56, 0.67};//用来模拟512个人脸特征值.
    
        string id2 = "bbb";//用来模拟32位的uuid.
        std::vector<float> feature2{1.12, 1.23, 1.34, 1.45, 1.56, 1.67};//用来模拟512个人脸特征值.
    
        string id3 = "ccc";//用来模拟32位的uuid.
        std::vector<float> feature3{2.12, 2.23, 2.34, 2.45, 2.56, 2.67};//用来模拟512个人脸特征值.
    
        string id4 = "ddd";//用来模拟32位的uuid.
        std::vector<float> feature4{3.12, 3.23, 3.34, 3.45, 3.56, 3.67};//用来模拟512个人脸特征值.
    
    
        //先把人脸特征值的float数组转成json,然后保存到数据库中。cjson的源码和例程在你自己的github上保存了
        cJSON *root1, *js_feature1;
        root1 = cJSON_CreateObject();
        cJSON_AddItemToObject(root1, "face_feature1", js_feature1 = cJSON_CreateArray());
        for(int i = 0; i < feature1.size(); i++)
        {
            cJSON_AddItemToArray(js_feature1, cJSON_CreateNumber(feature1.at(i)));    
        }    
        char *s1 = cJSON_PrintUnformatted(root1);    
        printf("s1:%s
    ", s1);
    
        //先把人脸特征值的float数组转成json,然后保存到数据库中。cjson的源码和例程在你自己的github上保存了
        cJSON *root2, *js_feature2;
        root2 = cJSON_CreateObject();
        cJSON_AddItemToObject(root2, "face_feature2", js_feature2 = cJSON_CreateArray());
        for(int i = 0; i < feature2.size(); i++)
        {
            cJSON_AddItemToArray(js_feature2, cJSON_CreateNumber(feature2.at(i)));    
        }    
        char *s2 = cJSON_PrintUnformatted(root2);    
        printf("s2:%s
    ", s2);
    
        //先把人脸特征值的float数组转成json,然后保存到数据库中。cjson的源码和例程在你自己的github上保存了
        cJSON *root3, *js_feature3;
        root3 = cJSON_CreateObject();
        cJSON_AddItemToObject(root3, "face_feature3", js_feature3 = cJSON_CreateArray());
        for(int i = 0; i < feature3.size(); i++)
        {
            cJSON_AddItemToArray(js_feature3, cJSON_CreateNumber(feature3.at(i)));    
        }    
        char *s3 = cJSON_PrintUnformatted(root3);    
        printf("s2:%s
    ", s3);
    
        //先把人脸特征值的float数组转成json,然后保存到数据库中。cjson的源码和例程在你自己的github上保存了
        cJSON *root4, *js_feature4;
        root4 = cJSON_CreateObject();
        cJSON_AddItemToObject(root4, "face_feature4", js_feature4 = cJSON_CreateArray());
        for(int i = 0; i < feature4.size(); i++)
        {
            cJSON_AddItemToArray(js_feature4, cJSON_CreateNumber(feature4.at(i)));    
        }    
        char *s4 = cJSON_PrintUnformatted(root4);    
        printf("s2:%s
    ", s4);
          
        sqlite3_initialize();
        rc = sqlite3_open_v2("featureList.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);//这时候登录嵌入式设备,你会看见创建了一个featureList.db的文件。
        if(rc != SQLITE_OK)
        {
            sqlite3_close_v2(db);
            printf("open featureList sql fail
    ");
        }
        else
        {
            printf("open featureList sql success
    ");
        }
    
        //这里的table名字featureList为前面open函数时的名字featureList,
        sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));"); 
        sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    
    
        //插入数据
        //ID传入NULL,那么会自动递增,另外这里的%s要用单引号括起来,
        sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id1.c_str(), s1);
        sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
    
        //ID传入NULL,那么会自动递增,另外这里的%s要用单引号括起来,
        sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id2.c_str(), s2);
        sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
    
        //ID传入NULL,那么会自动递增,另外这里的%s要用单引号括起来,
        sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id3.c_str(), s3);
        sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
    
        //ID传入NULL,那么会自动递增,另外这里的%s要用单引号括起来,
        sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s');", id4.c_str(), s4);
        sqlite3_exec( db , sql , 0 , 0 , &zErrMsg );
    
    
        //查询数据
        int nrow = 0, ncolumn = 0;
        char **azResult; 
        sprintf(sql, "SELECT * FROM featureList");
        sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
        printf("row:%d, column:%d
    ", nrow, ncolumn);
        for(int i = 0; i < (nrow + 1)*ncolumn; i++)
        {
            /**********************************************************************************************
            注意这里无论是ID,还是uuid,还是feature都是用%s打印的,那么说明虽然我们定义的时候ID是定义成了整型,
            但是实际上里面保存的时候是按照字符类型保存的,经测试,如果用用%d打印那么打印出来的是49 50这种,也就是1,2的ASCII码。
            ***********************************************************************************************/
            printf("azResult[%d] = %s
    ", i, azResult[i]);
        }
    
        string deleteId = "3";//定义成string类型,不要定义成int类型,
        printf("deleteId:%s
    ", deleteId.c_str());
        sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str());
        printf("delete sql is:%s
    ", sql);
        rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
        if(rc == SQLITE_OK)
        {
            //作用是重新构建数据库文件,回收空白空间,减小数据库文件的大小。
            printf("delete success
    ");
        }
        else
        {    
            printf("delete fail!
    ");
        }
    
        /**********************************************************************************
        如果本来的ID是1 2 3 4,我们把3删除,那么ID变为1 2 4,UPDATE语句的作用是把ID重新排序成1 2 3.
        刚开始这里写的是ID>1,这样是错误的,应该是从删除的元素开始ID=ID-1,删除元素前面的ID是不用改的。
        sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>1"); error
        ***********************************************************************************/
        sprintf(sql, "UPDATE featureList SET ID=ID-1 WHERE ID>%s", deleteId.c_str());
        rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    
        //删除之后再次查询看删除是否正常
        sprintf(sql, "SELECT * FROM featureList");
        sqlite3_get_table( db , sql , &azResult , &nrow , &ncolumn , &zErrMsg );
        printf("row:%d, column:%d
    ", nrow, ncolumn);
        for(int i = 0; i < (nrow + 1)*ncolumn; i++)
        {
            //注意这里是用%s打印的,虽然我们定义ID的时候是整型,但是实际上里面保存的时候是字符型的,
            printf("azResult[%d] = %s
    ", i, azResult[i]);
        }
    
        //释放空间
        delete[] sql;
        sqlite3_free_table(azResult);
        sqlite3_close(db);

    打印的log如下图:

     使用过程中遇到的问题:

    >>用上面的语句创建的数据库,uuid的类型是C++中string,而不是C语言中的char,

    sprintf(sql, "CREATE TABLE featureList(ID INTEGER PRIMARY KEY AUTOINCREMENT, uuid VARCHAR(10),feature VARCHAR(10));"); 
        sLabel = to_string(label);
        for(int i = 1; i <= nrow; i++)
        {
            printf("sLabel.c_str():%s
    ", sLabel.c_str());
            cout<<sLabel<<endl;
            printf("azResult[i*ncolumn + 1]:%s
    ", azResult[i*ncolumn + 1]);
    
            printf("strlen(sLabel.c_str()):%d
    ", strlen(sLabel.c_str()));
            printf("strlen(azResult[i*ncolumn + 1]):%d
    ", strlen(azResult[i*ncolumn + 1]));

    //if(sLabel.c_str() == azResult[i*ncolumn + 1]) //error if(sLabel == azResult[i*ncolumn + 1]) { deleteId = azResult[i*ncolumn]; printf("deleteId:%s ", deleteId.c_str()); sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str()); printf("delete sql is:%s ", sql); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); if(rc == SQLITE_OK) { printf("delete success "); } else { printf("delete fail! "); return -1; } } }

    上面的代码中,sLabel.c_str() 和 azResult[i*ncolumn + 1]用printf打印出来之后发现值是一样的,但是下面的 if(sLabel.c_str() == azResult[i*ncolumn + 1])却进不去,通过strlen发现两者的长度不一样,这是因为azResult[i*ncolumn + 1]是string类型,把if(sLabel.c_str() == azResult[i*ncolumn + 1])修改为if(sLabel == azResult[i*ncolumn + 1]),问题解决。

     >>数据库中保存中文信息

    labelname = "电脑";
    sprintf(sql, "INSERT INTO featureList VALUES(NULL, '%s','%s','%s');", sLabel.c_str(), s, labelname.c_str()); //sLabel要用c语言中的字符串形式,不能用C++中的string类型。

    就直接把中文赋值就好了,不需要进行相应的编码转换。

    作者:cumtchw
    出处:http://www.cnblogs.com/cumtchw/
    我的博客就是我的学习笔记,学习过程中看到好的博客也会转载过来,若有侵权,与我联系,我会及时删除。

  • 相关阅读:
    深入理解Java8中Stream的实现原理
    RocketMQ的顺序消费和事务消费
    Java 性能调优小技巧
    类加载机制基础
    十大经典排序算法
    分布式锁的几种常用实现方式
    python之接口开发
    python之urllib模块和requests模块
    python之time模块和hashlib模块
    python之os和sys模块的区别
  • 原文地址:https://www.cnblogs.com/cumtchw/p/11910026.html
Copyright © 2011-2022 走看看