基于OrangePi Zero 2实现垃圾分类智能垃圾桶项目(11)将指令来源和次数保存到数据库中(SQLite),指令来源和发出时间以及垃圾类型保存在文件中

news2025/1/21 1:04:26

SQLite(嵌入式数据库)

概念:

一种轻量级的关系型数据库管理系统,可以在应用程序中作为一个单独的组件运行,因此也被称为嵌入式数据库。与传统的客户端-服务器架构不同,SQLite 数据库存储在单个文件中,并直接与应用程序交互。它不需要专门的服务器进程或守护进程,也不需要网络通信,因此非常适合用于移动设备、桌面应用程序或其他小型嵌入式环境。
SQLite 使用 C API 进行访问,可以轻松地集成到任何支持 C 语言的环境中。它还提供了多种语言绑定,包括 Python、Java、PHP、Ruby 等,使得在这些语言中使用 SQLite 更加容易。 是一种高效、易用的嵌入式数据库解决方案,特别适合在资源有限的环境中使用。

选择SQLite原因:

SQLite 和 MySQL 都是非常流行的关系型数据库管理系统,但它们之间存在一些重要的差异:

1. 架构差异:MySQL 是一种典型的客户-服务器架构,由服务器进程来管理和处理所有数据库请求;而 SQLite 则没有独立的服务器进程,所有的操作都在客户端完成,可以直接与应用程序交互。
 2. 大小和性能差异:MySQL 提供了许多高级特性,例如表分区、索引优化等,而且能够处理大规模的数据集;而 SQLite 则更加简单和紧凑,更适合小规模的应用程序和嵌入式环境。
 3. 安全性和可靠性:MySQL 支持复杂的权限控制和安全机制;而 SQLite 主要依赖于操作系统和文件系统的安全措施。

总体来说,MySQL 更适合高性能、高并发的大规模应用,而 SQLite 则更适合资源受限的小型应用或嵌入式系统。

SQLite数据库安装:

1、执行 sqlite 指令

找不到相关内容说明没有安装过

2、执行安装指令

一般sqlite3的使用场景更多,运行“sudo apt-get -y install sqlite3

sudo apt-get -y install sqlite3

运行“sudo apt-get -y install sqlite” ,此时的版本是2.8.17,大家直接装sqlite3

运行上面指令时报错E:dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. 

“dpkg 已经被打断,您必须手动运行 'sudo dpkg --configure -a' 来纠正这个问题。” 这通常意味着你的 Ubuntu 系统正在尝试安装软件包的过程中遇到了某种错误,导致 dpkg (Debian 包管理器)无法正常工作。

按提示输入'sudo dpkg --configure -a'

再次输入安装指令

3、检查是否安装成功

完成后输入 sqlite3 查看

输入 .quit 可退出

 SQLite数据库基本操作:

在工作目录“/home/orangepi/”下创建一个文件夹,将数据库文件存放在这里:

1、数据库的创建/打开

法1:

在刚刚创建的文件夹里面

  • 输入“sqlite3” 进入数据库
  • 输入“.open test.db
  • 输入“.quit” 退出

执行“.open A.db”时,如果一个数据库A.db不存在则会创建并打开;若该数据库已经存在就会打开;且 “.open A.db”不是SQL命令,对应的C接口是sqlite3_open( )函数 

法2:

在刚刚创建的文件夹里面

  • 输入“sqlite3 test.db” 在命令运行当前窗口创建数据库test.db
  • 输入“.databases” 列出当前打开的数据库
  • 输入“.quit” 退出

 

2、表格的创建/打开

数据库表格的创建和结构体很类似,在实际中也经常将两者进行转换:

create table sf(age Integer,name char,height Integer); //在这里“int”应该写成“Integer”,且写在变量名的后方

打开刚刚创建的test.db数据库,并在其中添加一张名为sf的表格,表格有三个字段:整型的age和height,char型的name


 执行“create table AA(....)”时,如果表AA不存在则会创建并打开;若表格已经存在则会报错;且 “create table AA(....)”是SQL命令,对应的C接口是sqlite3_exec( )函数

3、插入数据

insert into sf values(18,'cxk',180); 
 
//也可以此一次只插入部分的字段内容,比如只插入name和score,不插入id
insert into sf(name,height) values('jg',190); //插入部分字段内容

4、查看数据库的记录

select * from sf; //查询所有字段的结果
select name,score from sf; //查询数据库中部分字段的内容

5、删除一条记录

delete from sf where name = cxk;

6、更改一条记录

update stu set name = 'majia' where score = 77;

7、增加一列

alter table stu add column sex char;

8、删除一张表

drop table stu;

9、输入错误指令处理方式

当输入了无法识别的指令,数据库会进入“...>”的状态:

输入“CTRL + Z” 就可以强制退出:


SQLite的编程操作

在学习了SQlite的基本操作之后,虽然有能力进行数据基本的增删改查,但是都需要输入“sqlite3”在数据库命令行来执行,我们希望实现的是更自动化的运行,比如程序在获取数据后可以自动写入数据库,这就需要学习如何打开/创建数据库的C接口:

打开/创建数据库的C接口

    sqlite3_open(const char *filename, sqlite3 **ppDb)

该指令打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据库连接对象。

    sqlite3_close(sqlite3*)

该指令关闭之前调用 sqlite3_open() 打开的数据库连接。
所有与连接相关的语句都应在连接关闭之前完成。 如果还有查询没有完成,sqlite3_close() 将返回 SQLITE_BUSY 禁止关闭的错误消息。

    const char *sqlite3_errmsg(sqlite3*);

该指令通常用来获取最近调用的API接口返回的错误代码
 错误代码:

 test1.c

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
 
int main(int argc, char** argv)
{
    sqlite3 *db;
    char *zErrMsg = 0;
    int ret;
 
    if(argc < 2){
        printf("Usage: %s xxx.db\n",argv[0]);
        return -1;
    }
 
    ret = sqlite3_open(argv[1], &db);
 
    if(ret != SQLITE_OK){
        printf("Can't open database: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Opened database successfully\n");
    }
    sqlite3_close(db);
    printf("close database\n");
}

 编译运行,gcc编译需要链接sqlite3的库,执行a.out时给程序指定数据库test.db

如果test.db本来就存在,那么“./a.out test.db” 也会成功运行,只不过从“创建test.db并关闭”变成了“打开test.db并关闭” 


sqlite3_exec函数的引入 & SELECT操作

`sqlite3_exec()` 是 SQLite 的一个内置函数,用于在指定的数据库连接上执行一个或多个 SQL 语句,并返回结果。它可以用于执行任何合法的 SQL 语句,包括 SELECT、INSERT、UPDATE 和 DELETE 等等。
使用 `sqlite3_exec()` 可以简化 SQLite 应用程序中的代码编写和维护工作,因为开发者只需要调用这个函数来执行 SQL 语句,而无需手动解析和处理查询结果。
此外,由于 `sqlite3_exec()` 支持回调函数,因此它还可以用于处理复杂的查询结果集。例如,当执行一个 SELECT 语句时,可以通过提供一个回调函数来处理每一行数据,以便实现更加灵活的数据处理方式。

sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char **errmsg)

其中:

  • `db`: 是一个已打开的数据库连接。
  • ` strSql`: 是要执行的 SQL 语句或多个 SQL 语句。
  • `callback`: 是一个回调函数,用于处理查询结果。如果不需要处理查询结果,则可以将其设置为 `NULL`。
  • `void*`: 是传递给回调函数的第一个参数。
  • `errmsg`: 是一个指针,用于接收错误消息。

该函数返回 SQLITE_OK(表示成功)、SQLITE_ERROR、SQLITE_INTERNAL、SQLITE_PERM、SQLITE_ABORT 等等,具体取决于操作的结果。

int callback(void *arg, int column_size, char *column_value[], char *column_name[])

用于处理 SQLite 查询结果的回调函数。当使用 sqlite3_exec() 执行包含 SELECT 语句或其他需要获取查询结果的操作时,可以将此回调函数作为参数传递给该函数。 

  •  第一个参数void *arg 是sqlite3_exec函数的第四个参数data
  • column_size:数据库的字段 数
  • column_value[ ]:列的值
  • column_name:字段名字

实现查看数据库记录指令 sqlite3_exec(db, "select * from sf;", callback, 0, &zErrMsg);

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
 
 
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);
 
	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}
 
 
int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;
 
	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}
 
	/*open database*/
	ret = sqlite3_open(argv[1], &db);
 
	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}
 
	/* execute sql statement */
	ret = sqlite3_exec(db, "select * from sf;", callback, 0, &zErrMsg);
 
	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}

 编译运行,gcc编译需要链接sqlite3的库,执行a.out时给程序指定查看的数据库test.db

 


创建表 & 插入数据

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
 
 
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);
 
	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}
 
 
int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;
	char *sql;
 
	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}
 
	/*open database*/
	ret = sqlite3_open(argv[1], &db);
 
	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}
 
	/* execute sql statement -- create table */ 
	sql = "CREATE TABLE COMPANY(" \
           "ID INT PRIMARY KEY NOT NULL," \
           "NAME CHAR(30) NOT NULL," \
           "AGE INT NOT NULL," \
           "ADDRESS CHAR(50)," \
           "SALARY REAL );";
 
	ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't create table: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Table create successfully\n");
	}
 
	/* execute sql statement -- insert data */
	sql = "insert into company values(1813,'company.1',3,'aaa street No.293',37732);";
 
    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't insert data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Inset data successfully\n");
    }
 
	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content: %s\n", sqlite3_errmsg(db));
        exit(0);
    }
 
 
	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}


UPDATE操作 & DELETE操作 

对于上一步创建的company表格,更新它的地址,然后删除这条记录

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
 
 
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);
 
	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}
 
 
int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;
	char *sql;
 
	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}
 
	/*open database*/
	ret = sqlite3_open(argv[1], &db);
 
	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}
 
	/* execute sql statement -- create table */ 
	sql = "CREATE TABLE COMPANY(" \
           "ID INT PRIMARY KEY NOT NULL," \
           "NAME CHAR(30) NOT NULL," \
           "AGE INT NOT NULL," \
           "ADDRESS CHAR(50)," \
           "SALARY REAL );";
 
	ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't create table: %s\n", sqlite3_errmsg(db));
		//exit(0); 这里将exit注释掉的原因是如果表格已经存在,不需要退出,而是继续执行即可
	}else{
		printf("Table create successfully\n");
	}
 
	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "before update", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content1: %s\n", sqlite3_errmsg(db));
        exit(0);
    }
 
	/* execute sql statement -- update data */
    sql = "update company set address = 'ccc street No.666' where id = 1813;";
 
    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't update data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Update data successfully\n");
    }
 
	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "after update", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content2: %s\n", sqlite3_errmsg(db));
        exit(0);
    }
 
	/* execute sql statement -- delete data */
    sql = "delete from company where id = 1813;";
 
    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't delete data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Delete data successfully\n");
    }
 
	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "after delete", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content3: %s\n", sqlite3_errmsg(db));
        exit(0);
    }
 
 
	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}

由于表格已经存在,所以创建表格的命令出错了,不过由于我的修改,代码会继续运行而不是直接exit;更新数据后,地址的确改变了;而删除数据后,由于本来就只有一条记录,所以此时company表没有数据,所以此时哪怕调用了“select * from company;” sqlite3_exec函数也不会调用callback来打印信息!
 




!!回归正题!!

代码实现:

项目源码:

https://pan.baidu.com/s/1KDznkE5dkpjBGxTbj9HnzQ
提取码:sail
 

1、使用数据库需包含头文件

2、定义变量

3、数据库和表创建函数

void create_db(){//创建/打开数据库并创建一个名为history的表格
    int ret;
    char *create_table_sql;
    //打开数据库
	ret = sqlite3_open("history.db", &db);
 
	if(ret != SQLITE_OK){
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Open database successfully\n");
	}
 
	//创建表格
	//create_table_sql = "create table history(cause char,count Integer);";
	create_table_sql = "CREATE TABLE HISTORY(" \
					   "CAUSE CHAR(30) PRIMARY KEY NOT NULL," \
					   "COUNT INT NOT NULL );" ;
 
	ret = sqlite3_exec(db, create_table_sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't create table: %s\n", sqlite3_errmsg(db));
		//exit(0);
	}else{
		printf("Table create successfully\n");
	}
}

4、表初始化函数(插入初始化数据)

void init_table() //用于初始化数据库中表格的值
{
	char *init_table_sql;
    int ret;
	init_table_sql = "insert into history values('socket',0);";
	ret = sqlite3_exec(db, init_table_sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't init table value: %s\n", sqlite3_errmsg(db));
	}
	init_table_sql = "insert into history values('sound',0);";
	ret = sqlite3_exec(db, init_table_sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't init table value: %s\n", sqlite3_errmsg(db));
	}
}

 

5、写入数据

在上一节将数据存储到文件中我们创建了一个线程record,这一节我们将指令来源和次数保存到数据库中(SQLite)、指令来源和发出时间以及垃圾类型保存在文件中这两个步骤都放到record里面运行

分别写两个函数功能是将数据写入文件和数据库

void data_file() //将历史记录写入文件的函数
{
	int hist_fd; // file description
    int ret;
	hist_fd = open("./history.txt",O_RDWR|O_CREAT|O_APPEND, 0666); //可读可写可打开的打开历史记录的文件,不存在就创建,且每次都追加写入
	if(hist_fd < 0){
		printf("fail to open history file!\n");
		fflush(stdout);
	}
	ret = write(hist_fd, &hist_whole, strlen(hist_whole));
	if(ret == -1){
		printf("fail to write history write to file!\n");
		fflush(stdout);
	}else{
		printf("write history to file successfully!\n");
        //文件内数据和数据库里面的数据一起显示有点乱我就先注释掉了
		/*printf("write the following history to file:\n");
		  printf("------------------------\n");
		  printf("%s",hist_whole);
		  printf("------------------------\n");*/
		fflush(stdout);
	}
	close(hist_fd);
	memset(hist_whole,'\0',sizeof(hist_whole)); //清空hist_whole!
 
}
 
void data_sql() //将历史记录写入数据库的函数
{
	char update_sql[128] = {'\0'};
    int ret;
   // printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
	sprintf(update_sql,"update history set count = %d where cause = 'socket';",sock_cmd);//客户端指令
    //printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);
    ret = sqlite3_exec(db, (const char *)update_sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't update date: %s\n", sqlite3_errmsg(db));
    }

	sprintf(update_sql,"update history set count = %d where cause = 'sound';",sond_cmd);//语音指令
    ret = sqlite3_exec(db, (const char *)update_sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't update date: %s\n", sqlite3_errmsg(db));
    }
 
	ret = sqlite3_exec(db, "select * from history;", callback, 0, &zErrMsg); //将数据库数据打印到屏幕
	if(ret != SQLITE_OK){
		printf("Can't show date: %s\n", sqlite3_errmsg(db));
	}

    //清零
    int sock_cmd = 0;//客户端指令
    int sond_cmd = 0;//语音指令
}

 将这两个函数在线程record里面调用

6、发生数据记录

我们统计指令来源(客户端、语音模块)在对应触发语句将各自变量+1

 



 

项目效果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1165463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虹科案例 | AR内窥镜手术应用为手术节约45分钟?

相信医疗从业者都知道&#xff0c;在手术室中有非常多的医疗器械屏幕&#xff0c;特别是内窥镜手术室中医生依赖这些内窥镜画面来帮助病患进行手术。但手术室空间有限&#xff0c;屏幕缩放位置相对固定&#xff0c;在特殊场景下医生观看内窥镜画面时无法关注到病患的状态。这存…

axios 实现请求 loading 效果

前景提要&#xff1a; ts 简易封装 axios&#xff0c;统一 API 实现在 config 中配置开关拦截器 loading 分为全屏 loading 和局部 loading。 axios 中设置 loading 只能设置全屏 loading&#xff0c;因为局部 loading 需要当前局部的 dom&#xff0c;在 axios 中显然拿不到发…

数据结构:排序干货!(7大排序汇总+快速排序的优化+计数排序+基数排序+桶排序)

目录 概念 插入排序 直接插入排序 希尔排序 选择排序 直接选择排序 双向选择排序 堆排序 交换排序 冒泡排序 快速排序 Hoare法 挖坑法 前后指针法 快排的优化 三数取中法 非递归快排 归并排序 分治算法二路归并 非递归归并 应用 排序总结 其他排序 计数…

记一次有趣的免杀探索

文章目录 前记查杀排查源码修改免杀效果测试 前记 evilhiding昨天被提issue不能绕过火绒了&#xff0c;于是今天更新了evilhiding v1.1&#xff0c;已经可以继续免杀了。 期待各位的stars&#xff0c;项目地址如下&#xff1a; https://github.com/coleak2021/evilhiding查杀…

【OJ比赛日历】快周末了,不来一场比赛吗? #11.04-11.10 #10场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-11-04&#xff08;周六&#xff09; #2场比赛2023-11-05…

科技云报道:大模型会给操作系统带来什么样的想象?

科技云报道原创。 在人工智能的发展历程中&#xff0c;大模型的出现标志着一个里程碑。 特别是近年来&#xff0c;诸如GPT-4、BERT等大模型的出现&#xff0c;不仅在自然语言处理、图像识别等领域取得了令人瞩目的成就&#xff0c;还推动了人工智能技术向更广泛的应用场景拓展…

IAR更新内置JLink

一、背景 IAR8.32,基于GD32F303CET6的工程&#xff0c;能正常使用JLINK进行debug and download&#xff0c;但在调试GD32F303CGT6时程序无法正常download且校验失败 GD32F303CET6&#xff1a;Flash--512K,RAM--64K GD32F303CET6&#xff1a;Flash--1M,RAM--96K 二、原因分析…

GZ035 5G组网与运维赛题第10套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第10套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

开关电源综合电气试验项目是什么?常规电源测试的标准和规范有哪些?

开关电源综合电气试验内容 1. 绝缘电阻和抗电强度测试 2. 输入浪涌电流测试 3. 输出电压、输入功率、输入功率因素、工作效率测试 4. 输出电压纹波及噪声测试 5. 输出过流保护测试 6. 短路保护测试 7. 输出电压过压保护测试 8. 过冲幅度及暂态恢复时间测试 9. 开机启动时间及关…

3dMax章鱼插件Octopus

3dMax章鱼插件Octopus 3dMax章鱼插件&#xff0c;不仅在视口中以饼状的形式&#xff0c;呼出各种属性参数&#xff0c;方便调用&#xff0c;而且是一个可编写脚本的框架&#xff0c;因此您有很多机会创建自己的菜单并轻松分发。整个OCTOPUS系统可以使用maxscript进行自定义&…

Linux shell编程学习笔记20:case ... esac、continue 和break语句

一、case ... esac语句说明 在实际编程中&#xff0c;我们有时会请到多条件多分支选择的情况&#xff0c;用if…else语句来嵌套处理不烦琐&#xff0c;于是JavaScript等语言提供了多选择语句switch ... case。与此类似&#xff0c;Linux Shell脚本编程中提供了case...in...esa…

睿趣科技:想知道开抖音小店的成本

随着互联网的发展&#xff0c;越来越多的人开始尝试通过开设网店来创业。抖音作为目前最受欢迎的短视频平台之一&#xff0c;也提供了开店的功能。那么&#xff0c;开一家抖音小店需要多少成本呢&#xff1f; 首先&#xff0c;我们需要了解的是&#xff0c;抖音小店的开店费用是…

Git 指令白雪警告!在IDEA中配置使用Git管理提交代码,无需繁杂指令

目录 1. 前言 2. Git 路径配置步骤 3. IDEA中使用Git管理项目 3.1 第一种做法 3.2 第二种做法 4. IDEA中提交代码和推送代码 5. 分支相关操作 5.1 创建分支 5.2 切换分支&#xff0c;删除分支 6. 拉取更新代码并处理分支冲突 1. 前言 相信有很多小伙伴在学习 Git 指…

libuv进程通信与管道描述符

libuv 提供了大量的子进程管理&#xff0c;抽象了平台差异并允许使用流或命名管道与子进程进行通信。Unix 中的一个常见习惯是每个进程只做一件事&#xff0c;并且把它做好。在这种情况下&#xff0c;一个进程通常会使用多个子进程来完成任务&#xff08;类似于在 shell 中使用…

【软件测试】个人博客项目测试报告

目录 1.报告概要 2、测试环境 3、手动测试用例编写 4、自动化测试用例 1.报告概要 测试对象&#xff1a;基于SSM项目的博客系统。 测试目的&#xff1a;检测博客项目是否符合预期&#xff0c;并且对测试知识进行练习和巩固。 测试点&#xff1a;主要针对常用的功能进行测…

rhcsa-vim

命令行的三种模式 将ets下的passwd文件复制到普通用户下面 编辑模式的快捷方式 a--光标后插入 A--行尾插入 o--光标所在上一行插入 O--光标所在上一行插入 i--光标前插入 I--行首插入 s--删除光标所在位然后进行插入模式 S--删除光标所在行然后进行插入 命令模式的快捷…

社交媒体欺诈乱象 | 每15人就有1人遭遇过网络欺诈!

目录 社交媒体的欺诈现象 欧盟要求科技公司加强虚假信息处理 借助技术识别虚假社交账号 据英国劳埃德银行&#xff08;TSB&#xff09;5月份发布的一份报告披露&#xff0c;社交媒体平台上的金融欺诈正在以令人担忧的速度增加&#xff0c;消费者应对Facebook、Instagram和Wh…

嵌入式linux常用的文件传输方式

做嵌入式就避免不了移植工作&#xff0c;所谓移植就是将交叉编译生成的可执行程序&#xff0c;库&#xff0c;配置文件等传输到开发板上进行工作。 常用传输方式有以下几种&#xff1a;1.串口传输 就是使用串口传输工具rz/sz; 该工具通过串口传输在SRT串口工具…

openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144)实现

文章目录 openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144)实现概述飞达控制底板硬件电路程序的修改END openpnp - 74路西门子飞达控制板(主控板STM32_NUCLEO-144)实现 概述 现在调试自己的openpnp设备, 在收尾, 将飞达控制板弄好, 能正常控制设备飞达安装平台上装满…

【Qt】QMainWidget中的栏和菜单

默认结构最复杂的标准窗口 提供了菜单栏, 工具栏, 状态栏, 停靠窗口菜单栏: 只能有一个, 创建的最上方工具栏: 可以有多个, 默认提供了一个, 窗口的上下左右都可以停靠状态栏: 只能有一个, 窗口最下方停靠窗口: 可以有多个, 默认没有提供, 窗口的上下左右都可以停靠 菜单栏 在…