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类型。
就直接把中文赋值就好了,不需要进行相应的编码转换。
作者:cumtchw
出处:http://www.cnblogs.com/cumtchw/
我的博客就是我的学习笔记,学习过程中看到好的博客也会转载过来,若有侵权,与我联系,我会及时删除。