通讯录实现【C语言】
目录
前言
一、整体逻辑分析
二、实现步骤
1、创建菜单和多次操作问题
2、创建通讯录
3、初始化通讯录
4、添加联系人
5、显示联系人
6、删除指定联系人
7、查找指定联系人
8、修改联系人信息
9、排序联系人信息
三、全部源码
前言
我们上期已经详细的介绍了自定义类型,本期我们来用学过的知识来做个小项目来练习练习。本期我们将用C语言实现通讯录静态版!后期介绍了动态内存管理和文件操作我们将会在此版本的基础上进行优化改进!
一、整体逻辑分析
我们还和以前实现三子棋和扫雷小项目一样,先对整体工程的逻辑尽可能详细的梳理,否则一开就是一顿狂敲,最后一走发现全是Bug这样就不好了!我们一开始尽可能的分析清楚,后面即使出现了问题也能快速确定!本期还是和往期一样采用多文件编程!OK,我们下面一起来梳理一下这个小项目的基本实现逻辑:
1、创建菜单和多次操作问题
2、创建通讯录
3、通讯录的初始化以及增删查改等操作
二、实现步骤
1、创建菜单和多次操作问题
我们期望当我们进行对通讯录操作时可以给我们在进行操作前给一个菜单功能我们操作!考虑到后面还要多次操作通讯录(增删查改等)我们结合起来很快想到用do..while循环处理最为合理,这里以前写过两三遍了我们直接上代码:
#include"contact.h"void menu()
{printf("*****************************************\n");printf("********* 1. add 2. del **********\n");printf("********* 3. search 4. modify **********\n");printf("********* 5. show 6. sort **********\n");printf("********* 0. exit **********\n");printf("*****************************************\n");
}void test()
{int input = 0;do{menu();printf("请选择操作数:> ");scanf("%d", &input);switch (input){case 1://addbreak;case 2://delbreak;case 3://searchbreak;case 4://modifybreak;case 5://showbreak;case 6://sortbreak;case 0:printf("退出成功!\n");break;default:printf("选择数非法!\n");break;}} while (input);
}int main()
{test();return 0;
}
看效果:
2、创建通讯录
我们在对通讯录进行各种操作前先得有个通讯录吧!通讯录的本质还是描述一个人的属性例如:姓名、年龄、性别、电话、住址等!这些都是不同的类型,我们很容易想到用结构体就能解决!但这只是描述一个人,你的通讯录不可能只有一个人吧应该是有很多个!而这些联系人又是同一类型,因此采用结构体数组来创建通讯录!
typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[15];char addr[20];
}PeoInfo;
这就是描述一个人基本属性的结构体!当创建好了这个结构体后,我们就可以在test.c这个文件中do..while循环那里可以创建结构体数组来作为通讯录了!
但这样写会有个问题就是,当你存入或删除联系人后想打印出来看看是此时通讯录中的联系人时应该打印多少?我们还想不知道。所以这里我们还得再定义一个变量sz来记录通讯录的大小!
其实我们发现,sz不仅是可以记录通讯录的大小,而且增加联系人的时候只需要增加到sz位置即可,增加一个sz++,当删除一个sz--;这样其实 sz和通讯录是绑定在一起的,我们不妨在对通讯录进行一层封装,把他也封装成一个结构体,一个成员是PeoInfo结构体数组,一个是记录通讯录大小的sz:
typedef struct PeoInfo
{char name[20];int age;char sex[5];char tele[15];char addr[20];
}PeoInfo;typedef struct Contact
{PeoInfo data[100];int sz;
}Contact;
然后再在test.c文件中创建即可!
OK!这个创建通讯录记好了!其实这里还可已在稍微优化一下:我们发现两个结构体中都出现了大量的常数,我们万一后期需求有变,这些都得改!因此为了后期修改方便,我们把这些都改成#define的常量,后期修改起来容易!这里你可能会说上期不是介绍了枚举吗,这里正好是多个常量枚举不是更好吗?这里枚举确实可以达到目的,但枚举是在没开始前就能列举出来所有可能,我们这个可不是!所以,这里不用枚举!
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 20
#define MAX 100typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;
这样才是当前逻辑下的最优代码!
3、初始化通讯录
当我们创建好了通讯录后我们先对其进行一个初始化!把结构体数组的每个元素都初始化为0,通讯录大小也置为0!因为我们要改变结构体的内容所以应该传地址!我们这里采用的是memset这个函数直接初始化为0,也可以用个循环来初始化!不了解memset的点击memset
void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}
4、添加联系人
我们前面已经说过了,只需要在sz的位置增加即可!但要考虑通讯录满的情况!
void AddContact(Contact* pc)
{assert(pc);//通讯录已满if (pc->sz == MAX){printf("通讯录已满,无法添加!\n");return;}//添加联系人printf("请输入联系人姓名:> ");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人年龄:> ");scanf("%d", &pc->data[pc->sz].age);printf("请输入联系人性别:> ");scanf("%s", pc->data[pc->sz].sex);printf("请输入联系人电话:> ");scanf("%s", pc->data[pc->sz].tele);printf("请输入联系人住址:> ");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("添加成功!\n");
}
OK,我们下面先来写一个显示联系人,来验证一下是否添加成功!
5、显示联系人
显示联系人就是把通讯录中的联系人打印在控制台!
void ShowContact(Contact* pc)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");for (int i = 0; i < pc->sz; i++){printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}
OK,我们来看看是否添加成功以及显示联系人!
OK,添加联系人和显示联系人都成功了!说明我们上面逻辑没有问题!
6、删除指定联系人
我们输入要删除的人的姓名,进行查找,找到了删除,否则输出没有此联系人!注意考虑通讯录为空的情况!这里提到了查找,这个查找和通讯录的那个查找有点不一样,这个是查找后返回下标即可,那个是还要打印联系人信息功能不一样。因此我们单独在封装一个函数!
//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;//找到了}}return -1;//没找到
}//删除联系人
void DelContact(Contact* pc)
{assert(pc);//通讯录为空if (pc->sz == 0){printf("通讯录为空,无法删除!\n");return;}char name[NAME_MAX] = { 0 };printf("请输入要删除人的姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){//删除for (int i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!\n");}else{printf("没有此联系人!\n");}
}
这里要注意的是比较字符串要用strcmp,不能用 == 这个我们在字符串函数和内存函数那一期详细介绍过!另外注意删除的时候那里下标越界问题!
看效果:
7、查找指定联系人
查找指定联系人还是先按指定方式进行查找, 找到了打印,否则输出没有此联系人!这里显示一个联系人的这个里后面修改联系人也可能要用所以我们为了方便把他封装成一个函数后面直接调用即可!
//显示单个联系人信息
void Print(const Contact* pc, int pos)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}//查找指定联系人
void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = -1;//初始化为-1表示没有此联系人for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){pos = i;//找到了break;}}if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");}
}
其实还可以在简洁一点,上面已经实现了FindContact我们可以用一下:
void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");}
}
看效果:
8、修改联系人信息
修改联系人信息这块就有很多可能,比如只修改一项例如名字或性别等,也有可能修改多项例如名字、年龄等,也有可能得全部修改这几种情况。当我们要修改之前群殴我们能还是期望有一个菜单供我们选择,当修改完一项后我们可能还要继续修改。基于此我们采用和test.c文件中得do...while循环+菜单!
//修改联系人信息菜单
void menu1()
{system("cls");printf("*****************************************\n");printf("********* 1. name 2. age **********\n");printf("********* 3. sex 4. tele **********\n");printf("********* 5. addr 6. all **********\n");printf("********* 0. exit **********\n");printf("*****************************************\n");
}//修改名字
void ModName(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人姓名:> ");scanf("%s", pc->data[ret].name);printf("修改成功!\n");
}//修改年龄
void ModAge(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人年龄:> ");scanf("%d", &pc->data[ret].age);printf("修改成功!\n");
}//修改性别
void ModSex(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人性别:> ");scanf("%s", &pc->data[ret].sex);printf("修改成功!\n");
}//修改电话
void ModTele(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人电话:> ");scanf("%s", &pc->data[ret].tele);printf("修改成功!\n");
}//修改住址
void ModAddr(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人住址:> ");scanf("%s", &pc->data[ret].addr);printf("修改成功!\n");
}void ModAll(Contact* pc, int ret)
{assert(pc);printf("请输入联系人姓名:> ");scanf("%s", pc->data[ret].name);printf("请输入联系人年龄:> ");scanf("%d", &pc->data[ret].age);printf("请输入联系人性别:> ");scanf("%s", pc->data[ret].sex);printf("请输入联系人电话:> ");scanf("%s", pc->data[ret].tele);printf("请输入联系人住址:> ");scanf("%s", pc->data[ret].addr);printf("修改成功!\n");
}//修改联系人
void ModContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("通讯录为空,无法修改!\n");return;}char name[NAME_MAX] = { 0 };printf("请输入要修改系人姓名:> ");scanf("%s", name);//判断是否有该联系人int ret = FindContact(pc, name);//有该联系人if (ret != -1){int n = 0;do{menu1();printf("请选择修改内容:> ");scanf("%d", &n);//修改switch (n){case 1:ModName(pc,ret);break;case 2:ModAge(pc, ret);break;case 3:ModSex(pc, ret);break;case 4:ModTele(pc, ret);break;case 5:ModAddr(pc, ret);break;case 6:ModAll(pc, ret);break;case 0:printf("修改结束!\n");break;default:printf("选择数非法!\n");break;}} while (n);}else{printf("没有此联系人!\n");}
}
看效果:(小编做了清屏)
修改前:
修改后:
OK,还是比较成功的!我们再来进行对他实现一下排序!
9、排序联系人信息
我们上面已经实现了通讯录的增删查改的基本功能!我们想让他再有一个排序功能,比如按名字排序,或年龄排序!我们在指针进阶那块介绍过回调函数,这里我们用qsort进行对通讯录排序!我们期望还是和上面一样一开始有个菜单选择!
//排序菜单
void menu2()
{system("cls");printf("**********************************\n");printf("***** 1. name 2. age **********\n");printf("**********************************\n");
}//名字比较函数
int cmp_name(const void* str1, const void* str2)
{//return strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name);return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}//名字排序
void SortName(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{//return ((PeoInfo*)str1)->age - ((PeoInfo*)str2)->age;return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//年龄排序
void SortAge(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}//排序联系人信息
void SortContact(Contact* pc)
{assert(pc);//判断为空if (pc->sz == 0){printf("通讯录为空,无法排序!\n");Sleep(3000);system("cls");return;}menu2();int n = 0;printf("请选择排序方式:> ");scanf("%d", &n);//排序switch (n){case 1:SortName(pc);system("cls");printf("排序成功!\n");break;case 2:SortAge(pc);system("cls");printf("排序成功!\n");break;default:printf("选择数非法!\n");Sleep(3000);system("cls");break;}
}
看效果:
排序前(年龄):
排序后(年龄):
排序前(名字):
排序后(名字):
OK,实现了排序!
三、全部源码
contact.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 15
#define ADDR_MAX 20
#define MAX 100typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;typedef struct Contact
{PeoInfo data[MAX];int sz;
}Contact;//初始化通讯录
void InitContact(Contact* pc);//添加联系人
void AddContact(Contact* pc);//显示联系人
void ShowContact(const Contact* pc);//删除联系人
void DelContact(Contact* pc);//查找指定联系人
void Search(const Contact* pc);//修改联系人
void ModContact(Contact* pc);//排序联系人信息
void SortContact(Contact* pc);
contact.c
#include"contact.h"//初始化通讯录
void InitContact(Contact* pc)
{assert(pc);memset(pc->data, 0, sizeof(pc->data));pc->sz = 0;
}//增加联系人
void AddContact(Contact* pc)
{assert(pc);//通讯录已满if (pc->sz == MAX){printf("通讯录已满,无法添加!\n");Sleep(2000);return;}//添加联系人printf("请输入联系人姓名:> ");scanf("%s", pc->data[pc->sz].name);printf("请输入联系人年龄:> ");scanf("%d", &pc->data[pc->sz].age);printf("请输入联系人性别:> ");scanf("%s", pc->data[pc->sz].sex);printf("请输入联系人电话:> ");scanf("%s", pc->data[pc->sz].tele);printf("请输入联系人住址:> ");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("添加成功!\n");Sleep(1000);
}//显示联系人
void ShowContact(const Contact* pc)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");for (int i = 0; i < pc->sz; i++){printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[i].name,pc->data[i].age,pc->data[i].sex,pc->data[i].tele,pc->data[i].addr);}
}//查找要删除的人并返回下标
int FindContact(const Contact* pc, const char* name)
{for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;//找到了}}return -1;//没找到
}//删除联系人
void DelContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除!\n");Sleep(2000);return;}char name[NAME_MAX] = { 0 };printf("请输入要删除人的姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){//删除for (int i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("成功删除联系人!\n");Sleep(1000);}else{printf("没有此联系人!\n");Sleep(2000);}
}//显示单个联系人信息
void Print(const Contact* pc, int pos)
{assert(pc);printf("%-s\t%-s\t%-5s\t%-15s\t%-20s\n", "姓名", "年龄", "性别", "电话", "住址");printf("%-s\t%-d\t%-5s\t%-15s\t%-20s\n",pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}//查找指定联系人
void Search(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找联系人姓名:> ");scanf("%s", name);int pos = FindContact(pc, name);if (pos != -1){Print(pc, pos);}else{printf("没有此联系人!\n");Sleep(2000);system("cls");}
}//修改联系人信息菜单
void menu1()
{system("cls");printf("*****************************************\n");printf("********* 1. name 2. age **********\n");printf("********* 3. sex 4. tele **********\n");printf("********* 5. addr 6. all **********\n");printf("********* 0. exit **********\n");printf("*****************************************\n");
}//修改名字
void ModName(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人姓名:> ");scanf("%s", pc->data[ret].name);
}//修改年龄
void ModAge(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人年龄:> ");scanf("%d", &pc->data[ret].age);
}//修改性别
void ModSex(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人性别:> ");scanf("%s", &pc->data[ret].sex);
}//修改电话
void ModTele(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人电话:> ");scanf("%s", &pc->data[ret].tele);
}//修改住址
void ModAddr(Contact* pc, int ret)
{assert(pc);printf("请输入修改后联系人住址:> ");scanf("%s", &pc->data[ret].addr);
}void ModAll(Contact* pc, int ret)
{assert(pc);printf("请输入联系人姓名:> ");scanf("%s", pc->data[ret].name);printf("请输入联系人年龄:> ");scanf("%d", &pc->data[ret].age);printf("请输入联系人性别:> ");scanf("%s", pc->data[ret].sex);printf("请输入联系人电话:> ");scanf("%s", pc->data[ret].tele);printf("请输入联系人住址:> ");scanf("%s", pc->data[ret].addr);
}//修改联系人
void ModContact(Contact* pc)
{assert(pc);//判断是否为空if (pc->sz == 0){printf("通讯录为空,无法修改!\n");Sleep(2000);system("cls");return;}char name[NAME_MAX] = { 0 };printf("请输入要修改系人姓名:> ");scanf("%s", name);//判断是否有该联系人int ret = FindContact(pc, name);//有该联系人if (ret != -1){int n = 0;do{menu1();Print(pc, ret);printf("请选择修改内容:> ");scanf("%d", &n);//修改switch (n){case 1:ModName(pc,ret);break;case 2:ModAge(pc, ret);break;case 3:ModSex(pc, ret);break;case 4:ModTele(pc, ret);break;case 5:ModAddr(pc, ret);break;case 6:ModAll(pc, ret);break;case 0:printf("修改结束!\n");Sleep(2000);system("cls");break;default:printf("选择数非法!\n");Sleep(2000);system("cls");break;}} while (n);}else{printf("没有此联系人!\n");Sleep(2000);system("cls");}
}//排序菜单
void menu2()
{system("cls");printf("**********************************\n");printf("***** 1. name 2. age **********\n");printf("**********************************\n");
}//名字比较函数
int cmp_name(const void* str1, const void* str2)
{//return strcmp(((PeoInfo*)str1)->name, ((PeoInfo*)str2)->name);return strcmp((((Contact*)str1)->data)->name, (((Contact*)str2)->data)->name);
}//名字排序
void SortName(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_name);
}//年龄比较函数
int cmp_age(const void* str1, const void* str2)
{//return ((PeoInfo*)str1)->age - ((PeoInfo*)str2)->age;return (((Contact*)str1)->data)->age - (((Contact*)str2)->data)->age;
}
//年龄排序
void SortAge(Contact* pc)
{qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_age);
}//排序联系人信息
void SortContact(Contact* pc)
{assert(pc);//判断为空if (pc->sz == 0){printf("通讯录为空,无法排序!\n");Sleep(3000);system("cls");return;}menu2();int n = 0;printf("请选择排序方式:> ");scanf("%d", &n);//排序switch (n){case 1:SortName(pc);system("cls");printf("排序成功!\n");break;case 2:SortAge(pc);system("cls");printf("排序成功!\n");break;default:printf("选择数非法!\n");Sleep(3000);system("cls");break;}
}
test.c
#include"contact.h"void menu()
{printf("*****************************************\n");printf("********* 1. add 2. del **********\n");printf("********* 3. search 4. modify **********\n");printf("********* 5. show 6. sort **********\n");printf("********* 0. exit **********\n");printf("*****************************************\n");
}void test()
{int input = 0;Contact con;InitContact(&con);do{menu();printf("请选择操作数:> ");scanf("%d", &input);switch (input){case 1:AddContact(&con);system("cls");break;case 2:DelContact(&con);system("cls"); break;case 3:system("cls");Search(&con);break;case 4:ModContact(&con);break;case 5:system("cls");ShowContact(&con);break;case 6:SortContact(&con);break;case 0:printf("退出成功!\n");break;default:printf("选择数非法!\n");break;}} while (input);
}int main()
{test();return 0;
}
OK,本期分享就到这里!好兄弟,我们下期再见!
相关文章:

通讯录实现【C语言】
目录 前言 一、整体逻辑分析 二、实现步骤 1、创建菜单和多次操作问题 2、创建通讯录 3、初始化通讯录 4、添加联系人 5、显示联系人 6、删除指定联系人 7、查找指定联系人 8、修改联系人信息 9、排序联系人信息 三、全部源码 前言 我们上期已经详细的介绍了自定…...

pcl欧式聚类
欧式聚类实现方法大致是: 1、找到空间中某点 p 1 p_1 p1,用KD-Tree找到离他最近的n个点,判断这n个点到 p 1 p_1 p1的距离。将距离小于阈值r的点 p 2 、 p 3 、 p 4 p_2、p_3、p_4 p2、p3、p4…放在类Q里 2、在 Q ( p 1 ) Q(p_1…...

macOS Ventura 13.5.1(22G90)发布(附黑/白苹果系统镜像地址)
系统镜像下载:百度:黑果魏叔 系统介绍 黑果魏叔 8 月 18 日消息,苹果今日向 Mac 电脑用户推送了 macOS 13.5.1 更新(内部版本号:22G90),本次更新距离上次发布隔了 24 天。 本次更新重点修复了…...

分布式监控平台——Zabbix
市场上常用的监控软件: 传统运维:zabbix、 Nagios 一、zabbix概述 作为一个运维,需要会使用监控系统查看服务器状态以及网站流量指标,利用监控系统的数据去了解上线发布的结果,和网站的健康状态。 利用一个优秀的监…...

【OpenGauss源码学习 —— 列存储(创建表)】
列存储 什么是列存储?语法实现语法格式参数说明示例源码分析(创建表)语法层(Gram.y)子模块(utility.cpp) 总结 声明:本文的部分内容参考了他人的文章。在编写过程中,我们…...

Jenkins 监控dist.zip文件内容发生变化 触发自动部署
为Jenkins添加plugin http://xx:xx/manage 创建一个任务 构建触发器 每3分钟扫描一次,发现指定文件build.zip文件的MD5发生变化后 触发任务...

Linux系列讲解 —— FTP协议的应用
简单介绍一下FTP文件传输协议在linux系统中的应用。 目录 0. 基本概念1. FTP Server1.1 安装FTP Server1.2 FTP Server开启和关闭1.3 查看FTP Server是否开启1.4 FTP服务器配置 2. FTP Client2.1 lftp2.2 ftp2.3 sftp2.4 文件资源管理器集成的ftp和sftp 3. ftp常用命令 0. 基本…...

Rancher-RKE-install 部署k8s集群
一、为什么用Rancher-RKE-install 1.CNCF认证的k8s安装程序。 2.有中文文档。 二、安装步骤 1.下载Rancher-Rke的二进制包-下面是项目的地址 GitHub - rancher/rke: Rancher Kubernetes Engine (RKE), an extremely simple, lightning fast Kubernetes distrib…...

PHP8的正则表达式-PHP8知识详解
在网页程序的时候,经常会有查找符合某些复杂规则的字符串的需求。正则表达式就是描述这些规则的工具。 正则表达式是把文本或者字符串按照一定的规范或模型表示的方法,经常用于文本的匹配操作。 例如:我们在填写手机号码的时候,…...

SpringCloud实用篇7——深入elasticsearch
目录 1 数据聚合1.1 聚合的种类1.2 DSL实现聚合1.2.1 Bucket聚合语法1.2.2 聚合结果排序1.2.3 限定聚合范围1.2.4 Metric聚合语法1.2.5.小结 1.3 RestAPI实现聚合1.3.1 API语法1.3.2 业务需求1.3.3 业务实现 2 自动补全2.1 拼音分词器2.2 自定义分词器2.3 自动补全查询2.4 实现…...

uni-app 经验分享,从入门到离职(二)—— tabBar 底部导航栏实战篇
文章目录 📋前言⏬关于专栏 🎯关于小程序 tabbar 的一些知识🎯创建一个基本的 tabBar📝最后 📋前言 这篇文章的内容主题是关于小程序的 tabBar 底部导航栏的入门使用和实战技巧。通过上一篇文章的基础,我们…...

Java虚拟机(JVM):内存区域
一、内存区域介绍 Java虚拟机(JVM)内存可以分为以下几个区域: 程序计数器(Program Counter Register):用于记录当前线程执行的字节码指令的地址,属于线程私有的区域。在任意时刻,一…...

11 - git stash 开发中临时加塞了紧急任务怎么处理
查看所有文章链接:(更新中)GIT常用场景- 目录 文章目录 开发中临时加塞了紧急任务怎么处理 开发中临时加塞了紧急任务怎么处理 当你此时工作区已经修改了 Readme 文件,然后突然需要解决其他问题(紧急问题、新任务&…...

高效的WMS系统手持盘点方案
WMS系统手持盘点就是指利用WMS系统支持的手持式电子盘点设备进行库存盘点的方式。 具体来说: - 手持盘点设备是一种小型的电子设备,具有移动条形码扫描功能,可以实时与WMS系统联通。 - WMS系统利用手持设备,可以给仓储人员下发具体的盘点任务,例如需要盘点的货位、商品等信息…...

Oracle分页技术
1、使用两层嵌套 SELECT *FROM (SELECT A.*, ROWNUM RNFROM (SELECT * FROM edw_t100_bal_all) AWHERE ROWNUM < 40)WHERE RN > 21; 2、使用between..and.. SELECT *FROM (SELECT A.*, ROWNUM RN FROM (SELECT * FROM edw_t100_bal_all) A)WHERE RN between 21 and 40…...

2023-08-15 Untiy进阶 C#知识补充6——C#7主要功能与语法
文章目录 一、字面值改进二、out 内部声明 / 弃元三、ref 返回值四、本地函数五、抛出表达式六、元组七、模式匹配 注意:在此仅提及 Unity 开发中会用到的一些功能和特性,对于不适合在 Unity 中使用的内容会忽略。 C# 7 对应 Unity 版本࿱…...

logstash配置文件
input { kafka { topics > “xxxx” bootstrap_servers > “ip:port” auto_offset_reset > “xxxx” group_id > “xxxx” consumer_threads > 3 codec > “json” } } filter { grok { match > { “message” > ‘%{IP:client_ip} - - [%{HTTPDATE:…...

docker搭建lnmp(nginx+mysql57+php7.4)
docker搭建lnmp(nginxmysql57php7.4) 1. 准备工作 docker安装 $ sudo yum update $ sudo sudo yum install -y yum-utils device-mapper-persistent-data lvm2 $ sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo $ sudo…...

专访 BlockPI:共建账户抽象未来的新一代 RPC 基础设施
在传统 RPC 服务板块上,开发者一直饱受故障风险、运行环境混乱等难题的折磨。实现 RPC 服务的去中心化,且保持成本优势和可扩展性,始终是区块链基础设施建设的重要命题之一。从 2018 年观察中心化 RPC 供应商服务现状开始,BlockPI…...

js fetch请求中断的几种方式
1、通过AbortController 这是官方标准手段,真正意义的阻止请求(不支持ie) 后端接口设置的两秒返回数据 function myFetch() {const controller new AbortController();const signal controller.signal;fetch(http://localhost:3000/aaa/…...

Python自动化实战之使用Selenium进行Web自动化详解
概要 为了完成一项重复的任务,你需要在网站上进行大量的点击和操作,每次都要浪费大量的时间和精力。Python的Selenium库就可以自动化完成这些任务。 在本篇文章中,我们将会介绍如何使用Python的Selenium库进行Web自动化,以及如何…...

“之江数据安全治理论坛”暨《浙江省汽车数据处理活动规定(专家建议稿)》研讨会顺利召开
研讨会主题 8月10日,“之江数据安全治理论坛”暨《浙江省汽车数据处理活动规定(专家建议稿)》研讨会在浙江大学计算机创新技术研究院举办。 本次研讨会的主题聚焦于“智能网联汽车的数据安全与数据合规”,邀请行业主管部门和数据…...

消息中间件面试题
异步发送(验证码、短信、邮件…) MYSQL和Redis,ES之间的数据同步 分布式事务 削峰填谷 RabbitMQ如何保证消息不丢失? 开启生产者确认机制,确保生产者的消息能到达队列 开启持久化功能,确保消息未消费前在队列中不会丢失 开启消费…...

麻辣烫数据可视化,麻辣烫市场将持续蓬勃发展
麻辣烫,这道源自中国的美食,早已成为人们生活中不可或缺的一部分。它独特的香辣口味,让人忍不住每每流连忘返。与人们的关系,简直如同挚友一般。每当寒冷的冬日或疲惫的时刻,麻辣烫总是悄然走进人们的心房,…...

大数据课程J1——Scala的概述
文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Scala的特点; ⚪ 了解Scala的开发环境搭建; ⚪ 了解Scala的开发工具; 一、概述 1.简介 Scala既是面向对象的语言,也是面向函数的语言。scala可以为你在做大量代码重用和扩展是提…...

第二章:25+ Python 数据操作教程(第十三节NUMPY 教程与练习)
NumPy(“Numerical Python”或“Numeric Python”的缩写)是 Python 中对数组和矩阵进行快速数学计算的最基本的软件包之一。在处理多维数据时它也非常有用。集成C、C++和FORTRAN工具是一件幸事。它还提供了许多傅里叶变换 (FT) 和线性代数函数。 为什么使用 NumPy 而不是列…...

【Java面试】如果一个线程两次调用start(),会出现什么问题?
这个问题出自阿里p6岗位第一面的提问,你会回答吗? 在Java里面,一个线程只能调用一次start()方法,第二次调用会抛出IllegalThreadStateException异常。 一个线程本身是具备一个生命周期的。 在Java里面,线程的生命周…...

购买steam余额有风险吗?以及N种被红锁的情况
购买steam余额有风险吗?以及N种被红锁的情况 无论是打游戏的玩家,还是像我们这类靠倒卖装备赚钱的小商贩,都面临充值美金余额的问题,我们现在主要是找的专业充值渠道做代充。 最近我发现群里有极个别学员通过自己的方法找到了一…...

使用 BERT 进行文本分类 (02/3)
一、说明 在使用BERT(1)进行文本分类中,我向您展示了一个BERT如何标记文本的示例。在下面的文章中,让我们更深入地研究是否可以使用 BERT 来预测文本是使用 PyTorch 传达积极还是消极的情绪。首先,我们需要准备数据…...

基于Hadoop的表级监管
现状 大数据平台中,采用hadoop的方式存储数据,hdfs本质上是文件系统,而文件系统对数据的监管能力有限,但是数据安全领域问题日渐凸显,现目前,大数据平台一般以分层结构进行授权,但是对于一线开发人员而言,是能够接触到整个大数据平台中的所有表的,那么如何实现这样一…...