> 文档中心 > C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】

C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】

C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】

  • 1. DustBaseShell.c
  • 2. DustBaseCore.c
  • 3. DustBaseShell模式使用截图
  • 4. DustBase典型使用流程
  • 5. DustBaseCore嵌入式使用
  • 6. DustBaseShell模式运行视频

【TDTX】
【C99】
【编译与运行环境】64位Windows操作系统,TDM-gcc 4.9.2 64bit(-std=c99)编译

项目Gitee仓库】DustBase,同时将V1.0版本也放在C语言-微项目。

【介绍】微尘数据库,一个十分简单轻量的非关系型——键值对数据库,纯C语言实现。

【使用方式】

  1. 由DustBaseShell.exe命令行交互式使用。由“.”前缀调用命令、由“$”前缀调用函数。(已实现
  2. 嵌入式使用。将DustBaseCore.c通过#include "DustBaseCore.c"的方式直接将数据库编译到用户程序中去。(已实现)
  3. 连接式用法。(待定)

【功能】
1.支持的函数

函数 作用
createDataBase 创建数据库
usingDataBase 指定要使用的数据库
clearUsingDataBase 清除使用中的数据库
deleteDataBase 删除某个未使用中的数据库
putString 存入键值对
deleteString 删除键值对
getString 获取键的值
setKeyValue 更改键的值
getKeyList 获取键名的列表

2.使用方法

  • 在DustBaseShell.exe命令行交互式环境中,使用’.'开头可以使用Shell里面的命令
  • 在DustBaseShell.exe命令行交互式环境中,使用’$'开头可以使用上述支持的函数里面的命令
  • 设置好环境变量后,DustBaseShell.exe支持带参启动!
  • 在嵌入式使用方法中,直接调用上述支持的函数即可

【版本】version 1.0

1. DustBaseShell.c

#include #include #include #include #include "DustBaseCore.c"char c;int count = 0;int isLegalparameter(char c){//判断参数是不是合法参数字符 if(c >= '0' && c <= '9'){return 1;}if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')){return 1;}return 0;}int checkParameter(char* command,int parastart,char** para){//command是用户输入的字符串//parastart是可能的函数参数起始位置//para将会指向合法的参数起始位置//检查单参数函数 int flag = 0;for(int i = parastart;i < strlen(command);i++){if(flag == 0 && command[i] != ' ' && isLegalparameter(command[i])){//过滤参数字符串的非法前缀 parastart = i;flag = 1;continue;}if(flag == 1 && !isLegalparameter(command[i])){//找到非空参数起始位置后,检查字符合法性 *para = NULL;return 0;}} //printf("start = %d\n",parastart);*para = &command[parastart];return 1;}int checkTwoParameter(char* command,int parastart,char** ppkey,char** ppvalue){int secondparastart = -1;int flag = 0;for(int i = parastart;i < strlen(command);i++){//判断该参数字符串有没有空格,即是否可能输入了两个参数,而非一个 if(flag == 0 && command[i] != ' '){flag = 1;}if(flag == 1 && command[i] == ' ' && i + 1 < strlen(command)){command[i] = '\0';secondparastart = i+1;}}if(secondparastart == -1){return 0;}//puts(&command[parastart]);//puts(&command[secondparastart]);int result = 0;result = checkParameter(command,parastart,ppkey);*ppvalue = &command[secondparastart];for(int i = 0;i < strlen(*ppvalue);i++){if((*ppvalue)[i] == '$'){return 0;}}return result;}void printHello(){puts("Welcome to DustBase v1.0.0.");puts("This is a very very lite datastore!");puts("Two type '.' and '$',$ use to function.");puts("Say \".help\" for more information.");}void printHelp(){puts(".help     Print this help message");puts(".databasesList names and files of attached databases");puts(".function List supported features");puts(".this     Introduce the DustBase");puts(".cls      Clear screen");puts(".restart  Restart DustBaseShell");puts(".quit     Quit the DustBaseShell");puts("$function parameter     For example:$createDataBase helloworld");}void printFunction(){puts("----------------------+---------------------------------------"); puts("|createDataBase|-创建数据库      |");puts("----------------------+---------------------------------------");puts("|usingDataBase |-指定要使用的数据库     |");puts("----------------------+---------------------------------------");puts("|clearUsingDataBase   |-清除使用中的数据库     |");puts("----------------------+---------------------------------------");puts("|deleteDataBase|-删除某个未使用中的数据库      |");puts("----------------------+---------------------------------------");puts("|putString     |-存入键值对      |");puts("----------------------+---------------------------------------");puts("|deleteString  |-删除键值对      |");puts("----------------------+---------------------------------------");puts("|getString     |-获取键的值      |");puts("----------------------+---------------------------------------");puts("|setKeyValue   |-更改键的值      |");puts("----------------------+---------------------------------------");puts("|getKeyList    |-获取键名的列表  |");puts("----------------------+---------------------------------------");puts("|getKeySeekIndex      |-获取[键的索引位置及键名组合]的列表   |");puts("----------------------+---------------------------------------");}void printIntroduce(){puts("- DustBase,微尘数据库!");puts("- 一个十分简单轻量的非关系型——键值对数据库,纯C语言实现!");puts("- 作者:CSDN/Gitee:TDTX/TDTXYZHH");}int main(int argc,char*argv[]){printHello();if(argc >= 2){if(argv[1] != NULL && !strcmp(".help",argv[1])){printf("DB> %s\n",argv[1]);printHelp();}if(argv[1] != NULL && !strcmp(".function",argv[1])){printf("DB> %s\n",argv[1]);printFunction();}if(argv[1] != NULL && !strcmp(".this",argv[1])){printf("DB> %s\n",argv[1]);printIntroduce();}if(argv[1] != NULL && !strcmp(".quit",argv[1])){printf("DB> %s\n",argv[1]);return 0;}}//puts("");while(1){printf("DB> ");while(1){c = fgetc(stdin);if(c == '\n'){break;}if(c == '.' && ftell(stdin) == 1){int commandsize = 0;char* command = (char*)malloc(0);while(1){c = fgetc(stdin);command = (char*)realloc(command,sizeof(char)*(commandsize + 1));commandsize++;if(c == '\n'){command[commandsize - 1] = '\0';break;}command[commandsize - 1] = c;}if(!strcmp("help",command)){printHelp();free(command);break;}else if(!strcmp("databases",command)){//puts("teset=====");DIR* dir = NULL;struct dirent* dt;int i = 0;dir = opendir("./");int flag = 0;puts("=====[In this folder]=====");while(dt = readdir(dir)){//print("hello");//printf("i = %d\n",i);char* filename = &(dt->d_name)[strlen(dt->d_name) - 4];if(!strcmp(filename,".tdb")){i++;printf("->%2d:%s\n",i,dt->d_name);flag = 1;}}if(flag == 0){puts("Info:NO DATABASE[.tdb]");}puts("=====[In this folder]=====");closedir(dir);free(command);break;}else if(!strcmp("function",command)){printFunction(); free(command);break;}else if(!strcmp("this",command)){printIntroduce();free(command);break;}else if(!strcmp("cls",command)){system("cls");free(command);break;}else if(!strcmp("restart",command)){char* t[] = {"DustBase",NULL};main(0,t);free(command);exit(0);break;}else if(!strcmp("quit",command)){free(command);return 0;}free(command);break;}else if(c == '$' && ftell(stdin) == 1){int commandsize = 0;char* command = (char*)malloc(0);while(1){c = fgetc(stdin);command = (char*)realloc(command,sizeof(char)*(commandsize + 1));commandsize++;if(c == '\n'){command[commandsize - 1] = '\0';break;}command[commandsize - 1] = c;}if(strstr(command,"createDataBase") != NULL){puts("create");if(strlen(command) > 15){if(command[14] != ' '){puts("Function:createDataBase input error,need space between function and parameter!");}else{char* parameter = &command[15];int i = checkParameter(command,15,&parameter);if(i == 0){puts("Function:createDataBase input error,parameters have illegal parameter!");}else{puts(parameter);createDataBase(parameter);}}}else{puts("Function:createDataBase input error,need parameter!");}free(command);break;}else if(strstr(command,"usingDataBase") != NULL){puts("use");if(strlen(command) > 14){if(command[13] != ' '){puts("Function:createDataBase input error,need space between function and parameter!");}else{char* parameter = &command[14];int i = checkParameter(command,14,&parameter);if(i == 0){puts("Function:createDataBase input error,parameters have illegal parameter!");}else{puts(parameter);usingDataBase(parameter);}}}else{puts("Function:createDataBase input error,need parameter!");}free(command);break;}else if(strstr(command,"clearUsingDataBase") != NULL){puts("clearusing");if(strlen(command) == 18){clearUsingDataBase();}else{puts("Function:createDataBase input error,don't need parameter!");}free(command);break;}else if(strstr(command,"deleteDataBase") != NULL){puts("deleteDataBase");if(strlen(command) > 15){if(command[14] != ' '){puts("Function:deleteDataBase input error,need space between function and parameter!");}else{char* parameter = &command[15];int i = checkParameter(command,15,&parameter);if(i == 0){puts("Function:deleteDataBase input error,parameters have illegal parameter!");}else{puts(parameter);deleteDataBase(parameter);}}}else{puts("Function:deleteDataBase input error,need parameter!");}free(command);break;}else if(strstr(command,"putString") != NULL){puts("putString");if(strlen(command) > 10){if(command[9] != ' '){puts("Function:putString input error,need space between function and parameter!");}else{char* pkey = &command[10];char* pvalue = NULL;int result = checkTwoParameter(command,10,&pkey,&pvalue);if(result == 0){puts("Function:putString input error,parameters have illegal parameter!");}else{//puts(pkey);//puts(pvalue);putString(pkey,pvalue);}}}else{puts("Function:putString input error,need parameter!");}free(command);break;}else if(strstr(command,"deleteString") != NULL){puts("deleteString");if(strlen(command) > 13){if(command[12] != ' '){puts("Function:deleteString input error,need space between function and parameter!");}else{char* parameter = &command[13];int i = checkParameter(command,13,&parameter);if(i == 0){puts("Function:deleteString input error,parameters have illegal parameter!");}else{puts(parameter);deleteString(parameter);}}}else{puts("Function:deleteString input error,need parameter!");}free(command);break;}else if(strstr(command,"getString") != NULL){puts("getString");if(strlen(command) > 10){if(command[9] != ' '){puts("Function:getString input error,need space between function and parameter!");}else{char* pkey = &command[10];char* pvalue = NULL;int result = checkTwoParameter(command,10,&pkey,&pvalue);if(result == 0){puts("Function:getString input error,parameters have illegal parameter!");}else{//puts(pkey);//puts(pvalue);//char* svalue = getString(pkey,pvalue);//puts(svalue);getString(pkey,pvalue);}}}else{puts("Function:getString input error,need parameter!");}free(command);break;}else if(strstr(command,"setKeyValue") != NULL){puts("setKeyValue");if(strlen(command) > 12){if(command[11] != ' '){puts("Function:setKeyValue input error,need space between function and parameter!");}else{char* pkey = &command[12];char* pvalue = NULL;int result = checkTwoParameter(command,12,&pkey,&pvalue);if(result == 0){puts("Function:setKeyValue input error,parameters have illegal parameter!");}else{//puts(pkey);//puts(pvalue);setKeyValue(pkey,pvalue);}}}else{puts("Function:setKeyValue input error,need parameter!");}free(command);break;}else if(strstr(command,"getKeyList") != NULL){puts("getKeyList");if(strlen(command) == 10){struct keylistinfo* keys = getKeyList();if(keys != NULL){for(int i = 0;i < keys->n;i++){if(i == 0){printf("[\"%s\"",(keys->keylist)[i]);}else{printf(",\"%s\"",(keys->keylist)[i]);}if(i == keys->n - 1){printf("]\n");}}}}else{puts("Function:createDataBase input error,don't need parameter!");}free(command);break;}free(command);break;}}}system("pause");return 0;}

2. DustBaseCore.c

#include #include #include struct keylistinfo{char** keylist;int n;};char rundatabasename[37] = {'\0'};//数据库名最多32字符 char* value = NULL;struct keylistinfo* keys = NULL;int connecDataBase();//待定int disconnectDataBase();//待定int createDataBase(char* databasename);int usingDataBase(char* databasename);int clearUsingDataBase();int deleteDataBase(char* databasename);int putString(char* key,char* value);int deleteString(char* key);char* getString(char* key,char* error);int setKeyValue(char* key,char* newvalue);struct keylistinfo* getKeyList();int getKeySeekIndex();//暂不实现 int connecDataBase(){//待定 }int disconnectDataBase(){//待定 } int createDataBase(char* databasename){int len = strlen(databasename);if(len > 32){puts("Warning:the length of database name exceeds the limit(32)");return 0;}char name[len+5];strcpy(name,databasename);name[len] = '.';name[len+1] = 't';name[len+1+1] = 'd';name[len+1+1+1] = 'b';name[len+1+1+1+1] = '\0';//puts(name);if(!access(name,F_OK)){puts("Error:the newdatabase exist!");return -1;}FILE* database = fopen(name,"a");if(database == NULL){puts("Error:create database fail!");return -1;}fflush(database);fclose(database);puts("Info:create database success!");return 1;}int usingDataBase(char* databasename){int len = strlen(databasename);if(len > 32){puts("Warning:the length of database name exceeds the limit(32)");return 0;}char name[len+5];strcpy(name,databasename);name[len] = '.';name[len+1] = 't';name[len+1+1] = 'd';name[len+1+1+1] = 'b';name[len+1+1+1+1] = '\0';//puts(name);if(access(name,F_OK)){puts("Error:the database doesn't exist!");return -1;}strcpy(rundatabasename,name);puts("Info:using database success!");char* value = (char*)malloc(0);keys = (struct keylistinfo*)malloc(sizeof(struct keylistinfo));keys->n = 0;keys->keylist = (char**)malloc(0);return 1;}int clearUsingDataBase(){if(strlen(rundatabasename) == 0){puts("Error:clear using databse fail,no database is using!");return 0;}rundatabasename[0] = '\0';free(value);value = NULL;for(int i = 0;i < keys->n;i++){free((keys->keylist)[i]);} free(keys->keylist);free(keys);keys = NULL;puts("Info:clear using databse success!");return 1;}int deleteDataBase(char* databasename){int len = strlen(databasename);if(len > 32){puts("Warning:the length of database name exceeds the limit(32)");return 0;}char name[len+5];strcpy(name,databasename);name[len] = '.';name[len+1] = 't';name[len+1+1] = 'd';name[len+1+1+1] = 'b';name[len+1+1+1+1] = '\0';//puts(name);if(access(name,F_OK)){puts("Error:the newdatabase doesn't exist!");return -1;}if(!strcmp(rundatabasename,name)){puts("Warning:the database is using,can not delete!");return 0;}if(remove(name) != 0){puts("Error:delete databse fail!");return -1;}puts("Info:delete databse success!");return 1;}int putString(char* key,char* value){if(rundatabasename[0] == '\0'){puts("Error:no database is using!");return -1;}if(strlen(key) > 32){puts("Warning:the length of key exceeds the limit(32)");return 0;}//puts(rundatabasename);for(int i = 0; i < strlen(value);i++){if(value[i] == '$'){puts("Warning:the value can not contain '$'!");return 0;}}FILE* database = fopen(rundatabasename,"a+");if(database == NULL){puts("Error:the database doesn't exist!");return -1;}char tkey[33];int cancopy = 0;int k = 0;char tc;while(1){//这里用来判断里面有没有该key,如果存在则不存入,没有则存入 tc = fgetc(database);if(tc == EOF){break;}if(tc == '$'){cancopy = 1;continue;}if(cancopy == 1){if(tc == ':'){tkey[k] = '\0';k = 0;cancopy = 0;//puts(tkey);if(!strcmp(key,tkey)){fclose(database);puts("Error:the key exists!");return -1;}tkey[0] = '\0';}else{tkey[k++] = tc;continue;}}}fprintf(database,"$%s:%s\n",key,value);fflush(database);fclose(database);puts("Info:putString success!");return 1;}int deleteString(char* key){if(rundatabasename[0] == '\0'){puts("Error:no database is using!");return -1;}if(strlen(key) > 32){puts("Warning:the length of key exceeds the limit(32)");return 0;}//puts(rundatabasename);FILE* database = fopen(rundatabasename,"a+");if(database == NULL){puts("Error:the database doesn't exist!");return -1;}char tkey[33];int cancopy = 0;int k = 0;char tc;int havekey = 0;int location = 0;while(1){//这里用来判断里面有没有该key,如果存在则执行删除,不存在则返回-1 tc = fgetc(database);if(tc == EOF){break;}if(tc == '$'){location = ftell(database);cancopy = 1;continue;}if(cancopy == 1){if(tc == ':'){tkey[k] = '\0';k = 0;cancopy = 0;//puts(tkey);if(!strcmp(key,tkey)){havekey = 1;//puts("Error:the key exists!");break;}tkey[0] = '\0';}else{tkey[k++] = tc;continue;}}}if(havekey == 1){int flag = 0;fseek(database,0,SEEK_SET);//将文件指针定位到起始位置FILE* temp = fopen("temp.tdb","w");if(temp == NULL){puts("Error:new temp-database fail!");fclose(database);return -1;}while(1){tc = fgetc(database);if(tc == EOF){break;}if(ftell(database) == location){flag = 1;}if(flag == 1){if((tc == '$' || tc == EOF) && ftell(database) > location){flag = 0;fputc(tc,temp);}}else{fputc(tc,temp);}}fclose(database);fclose(temp);remove(rundatabasename);rename("temp.tdb",rundatabasename);puts("Info:delete key-value success!");return 1;}else{fclose(database);puts("Error:the key doesn't exists,cannot delete key-vlaue!");return 0;}}char* getString(char* key,char* error){if(rundatabasename[0] == '\0'){puts("Error:no database is using!");return error;}if(strlen(key) > 32){puts("Warning:the length of key exceeds the limit(32)");return error;}//puts(rundatabasename);FILE* database = fopen(rundatabasename,"a+");if(database == NULL){puts("Error:the database doesn't exist!");return error;}char tkey[33];int cancopy = 0;int k = 0;char tc;int havekey = 0;int location = 0;while(1){//这里用来判断里面有没有该key,如果存在则执行获取值,不存在则返回error所指字符串 tc = fgetc(database);if(tc == EOF){break;}if(tc == '$'){cancopy = 1;continue;}if(cancopy == 1){if(tc == ':'){location = ftell(database);tkey[k] = '\0';k = 0;cancopy = 0;//puts(tkey);if(!strcmp(key,tkey)){havekey = 1;//puts("Error:the key exists!");break;}tkey[0] = '\0';}else{tkey[k++] = tc;continue;}}}k = 0;if(havekey == 1){fseek(database,location,SEEK_SET);while(1){tc = fgetc(database);if(tc == '$' || tc == EOF){break;}value = (char*)realloc(value,++k);value[k - 1] = tc;}value[k] = '\0';puts("value is:");puts(value);fclose(database);return value;}else{fclose(database);puts("Error:the key doesn't exists,cannot get vlaue!");return 0;}}int setKeyValue(char* key,char* newvalue){if(rundatabasename[0] == '\0'){puts("Error:no database is using!");return -1;}if(strlen(key) > 32){puts("Warning:the length of key exceeds the limit(32)");return 0;}//puts(rundatabasename);for(int i = 0; i < strlen(value);i++){if(value[i] == '$'){puts("Warning:the value can not contain '$'!");return 0;}}FILE* database = fopen(rundatabasename,"a+");if(database == NULL){puts("Error:the database doesn't exist!");return -1;}char tkey[33];int cancopy = 0;int k = 0;char tc;int havekey = 0;int location = 0;while(1){//这里用来判断里面有没有该key,如果存在则执行设置该key的value,不存在则返回0 tc = fgetc(database);if(tc == EOF){break;}if(tc == '$'){cancopy = 1;continue;}if(cancopy == 1){if(tc == ':'){location = ftell(database);tkey[k] = '\0';k = 0;cancopy = 0;//puts(tkey);if(!strcmp(key,tkey)){havekey = 1;//puts("Error:the key exists!");break;}tkey[0] = '\0';}else{tkey[k++] = tc;continue;}}}if(havekey == 1){int flag = 0;fseek(database,0,SEEK_SET);//将文件指针定位到起始位置FILE* temp = fopen("settemp.tdb","w");if(temp == NULL){puts("Error:new settemp-database fail!");fclose(database);return -1;}while(1){tc = fgetc(database);if(tc == EOF){break;}if(ftell(database) == location){fputc(tc,temp);flag = 1;int len = strlen(newvalue);for(int i = 0;i < len;i++){fputc(newvalue[i],temp);}fputc('\n',temp);}if(flag == 1){if((tc == '$' || tc == EOF) && ftell(database) > location){flag = 0;fputc(tc,temp);}}else{fputc(tc,temp);}}fclose(database);fclose(temp);remove(rundatabasename);rename("settemp.tdb",rundatabasename);puts("Info:set the key's new value success!");return 1;}else{fclose(database);puts("Error:the key doesn't exists,cannot set set the key's new value!");return 0;}}struct keylistinfo* getKeyList(){if(rundatabasename[0] == '\0'){puts("Error:no database is using!");return NULL;}//puts(rundatabasename);FILE* database = fopen(rundatabasename,"a+");if(database == NULL){puts("Error:the database doesn't exist!");return NULL;}if(keys->n != 0){for(int i = 0;i < keys->n;i++){free((keys->keylist)[i]);}keys->keylist = (char**)realloc(keys->keylist,0);keys->n = 0;}char tkey[33];int cancopy = 0;int k = 0;char tc;int location = 0;while(1){tc = fgetc(database);if(tc == EOF){break;}if(tc == '$'){location = ftell(database);cancopy = 1;continue;}if(cancopy == 1){if(tc == ':'){tkey[k] = '\0';k = 0;cancopy = 0;//puts(tkey);keys->keylist = (char**)realloc(keys->keylist,sizeof(char*)*(keys->n + 1));(keys->n)++;char* thiskey = (char*)malloc(strlen(tkey)*sizeof(char));strcpy(thiskey,tkey);//printf("检查thiskey:%s\n",thiskey);(keys->keylist)[keys->n - 1] = thiskey;tkey[0] = '\0';}else{tkey[k++] = tc;continue;}}}fclose(database);return keys;}int getKeySeekIndex(){//暂不实现 }

3. DustBaseShell模式使用截图

C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】
C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】

4. DustBase典型使用流程

  1. int createDataBase(char* databasename);//创建数据库

  2. int usingDataBase(char* databasename);//使用数据库

  3. 使用下列数据库操作函数:
    int putString(char* key,char* value);
    int deleteString(char* key);
    char* getString(char* key,char* error);
    int setKeyValue(char* key,char* newvalue);
    struct keylistinfo* getKeyList();

  4. int clearUsingDataBase();//清除使用的数据库

  5. int deleteDataBase(char* databasename);//删除未使用中的数据库

5. DustBaseCore嵌入式使用

测试文件:importtest.c

#include #include "DustBaseCore.c"int main(){createDataBase("useimport999");usingDataBase("useimport999");putString("godd1","dadasdhjuhfas\ndadasd\tdada8977465=");putString("peoo","dersaasdasdewqdad");putString("qdwqd","cfasdsadad");getString("godd1","error");struct keylistinfo* keys = getKeyList();if(keys != NULL){for(int i = 0;i < keys->n;i++){if(i == 0){printf("[\"%s\"",(keys->keylist)[i]);}else{printf(",\"%s\"",(keys->keylist)[i]);}if(i == keys->n - 1){printf("]\n");}}}setKeyValue("godd1","this is new value!!!!");keys = getKeyList();if(keys != NULL){for(int i = 0;i < keys->n;i++){printf("%s:%s",(keys->keylist)[i],getString((keys->keylist)[i],"error"));}}clearUsingDataBase();system("pause");return 0;}

运行截图:
C语言【微项目17】—DustBase微尘数据库[自制键值对数据库][超轻量]【2022-03-23】

6. DustBaseShell模式运行视频

DustBase--微尘数据库,一个十分简单轻量的非关系型——键值对数据库,纯C语言实现!