当前位置: 首页 > article >正文

从数据库中查找单词

我们知道,从文件中查找是一行一行的查找匹配,但是数据库就可以快速查找,节约时间;

我们先来讲一下大概思路(所有都为C语言);

首先使用access函数判断数据库字典有没有被创建,如果创建了就跳过创建这个步骤,要不然每次加载都会耗费很多时间(几乎1-2分钟)(等待的过程蛮漫长的);

这是使用到的头文件;

#include <sqlite3.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
/*********************定义的全局变量函数***************/
sqlite3 *pdb;
char temp[4096] = {0};
char *errmsg = NULL;

这是主函数的逻辑;

int main(void)
{
    int ret = 0;
    int ok = 0;

    ok = access("/home/linux/Desktop/2024/20240822/dict.db",F_OK); //这个路径是我自己的,可以替换
    if(0 == ok)  //access函数的特性,F_OK是用于查看该文件是否存在,成功返回0
    {
        ret = Open();  //打开数据库
        if(ret == -1)  //错误处理
        {
            fprintf(stderr,"fail to sqlite_open:%s\n",sqlite3_errmsg(pdb));
            return -1;
        }
        ret = word_put();  //传入想要查询的单词
        if(ret == -1)        //错误处理
        {
            fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
            sqlite3_free(errmsg);   //释放掉错误码的空间
            sqlite3_close(pdb);    //关闭数据库
            return -1;
        }
        return 0;
    }

    if(-1 == ok)
    {
        printf("不存在,开始创建\n");
        ret = Open();
        if(ret == -1)
        {
            fprintf(stderr,"fail to sqlite_open:%s\n",sqlite3_errmsg(pdb));
            return -1;
        }
        ret = word_creat();
        if(ret == -1)
        {
            return -1;
        }
        ret = word_put();
        if(ret == -1)
        {
            fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
            sqlite3_free(errmsg);
            sqlite3_close(pdb);
            return -1;
        }
    }
    sqlite3_close(pdb);
    return 0;
}

打开数据库的函数;

/****************************************************/
int Open(void)
{
    int ret = 0;
    ret = sqlite3_open("dict.db",&pdb);
    if(ret != SQLITE_OK)
    {
        return -1;
    }
    return 0;
}
/*****************************************************/

创建dict 数据库,并将字典加载到数据库中;

/*************************************************/
int word_creat()
{
    int ret = 0;
    FILE *fp = NULL;;
    char *nsize = NULL;
    char *pword = NULL;
    char *pmean = NULL;
    char tempword[1024] = {0};
    sprintf(temp,"create table dict(id integer primary key asc, word text, mean text)");
    ret = sqlite3_exec(pdb,temp,NULL,NULL,&errmsg); //使用sqlite3_exec函数执行语句
    if(ret != SQLITE_OK)  //错误处理
    {
        fprintf(stderr,"fail to sqlite_exec:%s\n",errmsg);
        sqlite3_free(errmsg);
        sqlite3_close(pdb);
        return -1;
    }
    fp = fopen("dict.txt","r");  //打开字典文件
    if(NULL == fp)
    {
        perror("fail to fopen dict.txt");
        sqlite3_close(pdb);
        return -1;
    }

    while(1)
    {
        memset(temp,0,sizeof(temp));   //对temp清零
        nsize = fgets(temp,sizeof(temp),fp);  //读取一行字符串
        temp[strlen(temp)-1] = '\0';
        if(nsize == NULL)
        {
            break;
        }
        pword = strtok(temp," ");   //进行分割
        pmean = strtok(NULL,"\r\n");
        sprintf(tempword,"insert into dict values (NULL,\"%s\",\"%s\")",pword,pmean);
        ret = sqlite3_exec(pdb,tempword,NULL,NULL,&errmsg);  //插入单词和含义
        if(ret != SQLITE_OK)
        {
            fprintf(stderr,"fail to sqlite_exec11:%s\n",errmsg);
            sqlite3_free(errmsg);
            sqlite3_close(pdb);
            return -1;
        }
    }
    fclose(fp);  
    return 0;
}
/*****************************************************/

查询单词;

/*****************************************************/
int word_put(void)
{
    int ret = 0;
    char input[1024] = {0};
    printf("录入完成!\n");
    memset(temp,0,sizeof(temp));
    fgets(temp,sizeof(temp),stdin);
    temp[strlen(temp)-1] = '\0';
    sprintf(input,"select word ,mean from dict where word = \"%s\"",temp);
    ret = sqlite3_exec(pdb,input,callback,NULL,&errmsg);
    if(ret != SQLITE_OK)
    {
        return -1;
    }
    return 0;
}
/*************************************************/

回调函数;

/**************************************************/
int callback(void * arg, int column, char **pcontet, char **ptitle)
{
    printf("%s : %s\n",pcontet[0],pcontet[1]);  //打印查到的单词和意思
    return 0;
}
/****************************************************/

这里面有几个有意思的点:

1.字符串的分割;

        因为原字典里的单词长这样:a                indef art one \r\n,

        用strtok分割,第一次分割空格之前的单词,第二次分割到\r\n;

2.在加载过程中显示加载进度;

        由于加载过程中太无聊,想要一点动态显示加载进度可以这样做,

//加载单词文件时,fseek将光标偏移到最末尾      

    fseek(fp, 0, SEEK_END);

//ftell获得光表的偏移量

    tlen = ftell(fp);

//再将光标定义回开头

    rewind(fp);

这样就获得了整个文件的大小;

//读取一行信息

        pret = fgets(tmpbuff, sizeof(tmpbuff), fp);

//获得这一行的大小

        clen = ftell(fp);

//转换成double型打印

        printf("已加载: %.2lf\r", (double)clen / (double)tlen * 100);

//刷新

        fflush(fp);

加上循环,这样就可以动态显示加载进度了;

3.显示加载用时;

想要显示整个文件加载到数据库需要多长时间可以这样做;

在加载文件之前使用gettimeofday; 

gettimeofday(&start, NULL);

在加载文件完成后使用;

 gettimeofday(&end, NULL);


打印;
printf("加载数据库文件成功! 耗时: %.2lf s  CPU耗时:%.2lf s\n", ((double)(end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec)) / 1000000,((double)(cpuend - cpustart)) / CLOCKS_PER_SEC);

4.使用makefile

因为这个程序调用了sqlite3库,所以在编译时需要加上 -lsqlite3,要是每次都加可能比较麻烦,所以我们创建makefile文件;

.PHONY:是一个伪指令,

a.out:select_world.c
	gcc $^ -o $@ -lsqlite3
.PHONY:
clean:
	rm a.out

5.如何将加载时间压缩到极致;

第一种方法:关闭磁盘写同步

        PRAGMA synchronous = NORMAL;

第二种方法:开启事务

        begin 和 commit;

第三种办法:使用预处理SQL语句机制实现提升数据库效率

今天就到这里啦!


http://www.kler.cn/news/283386.html

相关文章:

  • JAVA电子器件制造行业生产管理系统计算机毕设计算机毕业设计
  • 2024.8.30(使用docker部署project-exam-system)
  • 20.神经网络 - 搭建小实战和 Sequential 的使用
  • 自动化数据汇总:使用Python从多个数据源汇总数据
  • linux查找mysql日志
  • 艾体宝干货丨Redis与MongoDB的区别
  • 自动化通过cmd命令行并以特定账户连接到远程机器
  • 【香橙派系列教程】(二十一) 基于OrangePi Zero2的系统移植— 交叉编译工具链配置
  • 【C++ 面试 - 内存管理】每日 3 题(九)
  • 算法中常用的排序
  • 云计算实训37——Dockerfile的应用+私有仓库的创建与管理
  • 更改图片中的部分颜色及修改图片的背景色
  • 如何知道当前网卡连接的下位机的IP,通过工具实现
  • 代码随想录 | 贪心算法总结
  • 负载均衡OJ项目详细解剖
  • Error running tomcat: Can‘t find catalina.jar
  • 给自己复盘的随想录笔记-哈希表
  • Furion+SqlSugar+Swagger企业级后端工程师 - 学习路线总目录
  • 【IEEE独立出版,快检索 | 高录用】第五届IEEE信息科学与教育国际学术会议(ICISE-IE 2024,12月20-22)
  • 如何禁止电脑访问网站
  • 一维/二维高斯分布的负对数似然推导
  • 【日常记录-Linux】.tar.xz、.tar.bz2、tar.gz解压
  • 8、嵌套循环 - 循环中的循环 - 课件
  • MySQL表分区与分表:概念、规则及应用案例
  • MyPrint打印设计器(四)vue3 函数式调用组件
  • vue3 使用vue-masonry加载更多,重新渲染
  • Java设计模式之装饰器模式详细讲解和案例示范
  • 深度学习:图像数据分析的革命
  • HTML静态网页成品作业(HTML+CSS)——电影肖申克的救赎介绍设计制作(1个页面)
  • jmeter连接mysql数据库以及常规用法