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\n", 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\n", 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\n", 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\n", 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\n");
    }
    else
    {
        printf("open featureList sql success\n");
    }

    //这里的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\n", 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\n", i, azResult[i]);
    }

    string deleteId = "3";//定义成string类型,不要定义成int类型,
    printf("deleteId:%s\n", deleteId.c_str());
    sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str());
    printf("delete sql is:%s\n", sql);
    rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    if(rc == SQLITE_OK)
    {
        //作用是重新构建数据库文件,回收空白空间,减小数据库文件的大小。
        printf("delete success\n");
    }
    else
    {    
        printf("delete fail!\n");
    }

    /**********************************************************************************
    如果本来的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\n", nrow, ncolumn);
    for(int i = 0; i < (nrow + 1)*ncolumn; i++)
    {
        //注意这里是用%s打印的,虽然我们定义ID的时候是整型,但是实际上里面保存的时候是字符型的,
        printf("azResult[%d] = %s\n", 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\n", sLabel.c_str());
        cout<<sLabel<<endl;
        printf("azResult[i*ncolumn + 1]:%s\n", azResult[i*ncolumn + 1]);

        printf("strlen(sLabel.c_str()):%d\n", strlen(sLabel.c_str()));
        printf("strlen(azResult[i*ncolumn + 1]):%d\n", 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\n", deleteId.c_str()); sprintf(sql, "DELETE FROM featureList WHERE ID = %s", deleteId.c_str()); printf("delete sql is:%s\n", sql); rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg); if(rc == SQLITE_OK) { printf("delete success\n"); } else { printf("delete fail!\n"); 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类型。

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

posted @ 2019-11-22 10:20  cumtchw  阅读(1824)  评论(0编辑  收藏  举报