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/
    我的博客就是我的学习笔记,学习过程中看到好的博客也会转载过来,若有侵权,与我联系,我会及时删除。

  • 相关阅读:
    LeetCode 623. Add One Row to Tree
    LeetCode 894. All Possible Full Binary Trees
    LeetCode 988. Smallest String Starting From Leaf
    LeetCode 979. Distribute Coins in Binary Tree
    LeetCode 814. Binary Tree Pruning
    LeetCode 951. Flip Equivalent Binary Trees
    LeetCode 426. Convert Binary Search Tree to Sorted Doubly Linked List
    LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal
    LeetCode 687. Longest Univalue Path
    LeetCode 428. Serialize and Deserialize N-ary Tree
  • 原文地址:https://www.cnblogs.com/cumtchw/p/11910026.html
Copyright © 2011-2022 走看看