【Linux】基础IO--文件基础知识/文件操作/文件描述符
文章目录
- 一、文件相关基础知识
- 二、文件操作
- 1.C语言文件操作
- 2.操作系统文件操作
- 2.1 比特位传递选项
- 2.2 文件相关系统调用
- 2.3 文件操作接口的使用
- 三、文件描述符fd
- 1.什么是文件描述符
- 2.文件描述符的分配规则
一、文件相关基础知识
我们对文件有如下的认识:
1.文件 = 文件内容 + 文件属性,即文件包括文件的内容和属性两个部分
2.空文件只是文件的内容为空,但是文件的属性不为空,所以空文件也需要占据磁盘的空间
3.由于文件包括内容和属性,那么我们对文件的操作可以分为对文件内容非操作,对文件的属性进行操作以及对文件的内容和属性进行操作
3.Linux/windows中目录都采用多叉树的形式进行表示,即树的中间节点表示目录,树的叶子节点表示文件,所以我们可以使用文件路径+文件名来唯一的标识一个文件
4.在对文件进行访问的时候,如果没有指定文件的路径,那么默认在当前路径下对文件进行访问,当前路径指的是当前进程所在的工作路径
5.在C语言中,当我们把fopen,fclose,fwrite,fread等函数接口的程序编译链接形成可执行程序,如果我们运行该可执行程序,那么对应的函数就不会被调用,则对应的文件操作也就不会被执行,因为函数在运行时才会建立栈帧,所以对文件的操作本质上是进程对文件的操作
6.我们知道,我们要访问一个文件,那么就必须先打开这个文件,而文件存储在磁盘上,由于计算机结构的原因,磁盘上的文件必须通过OS才能和进程进行交互,所以文件打开是由用户进程和OS配合来完成的—用户进程调用文件的接口,OS系统实现这些系统调用接口
7.磁盘上存在许许多多的文件,并不是所有的这些文件都被打开了,所以文件分为被打开的文件和没有被打开的文件,那些没有被打开的文件被成为文件系统
所以,文件操作的本质是进程与被打开文件的关系
二、文件操作
在谈论文件操作之前,我们需要了解 语言层面上的文件操作与操作系统层面上的文件操作的关系
我们知道,每一种语言都有其对应的文件操作,包括面向过程语言C,面向对象语言C++/java,静态编译语言go,解释型语言python,甚至包括脚本语言shell等等,但是每一种语言对文件操作提供的接口都不相同,这样就会导致我们的学习成本变得很高。
站在语言的角度我们觉得是这样的,但是站在操作系统的角度就不是这样了 ,我们知道计算机的软硬件体系结构之后,就会知道操作系统为了同时满足 保护自身安全 与 为上层用户提供良好的(稳定的,安全的,高效的)服务,会给用户提供访问软硬件的系统调用接口,同时,为了降低用户使用成本,人们又在系统调用接口的基础上开发了用户操作接口,其中包括shell外壳与各种语言的函数库,而用户就是通过调用用户操作接口类完成指令,开发与管理等操作

也就是说,站在操作系统的角度,虽然每一种语言的文件操作接口都不一样,但是这些接口底层调用的一定是同一种系统调用接口,因为操作系统是计算机管理软硬件资源的软件,进程想要访问文件只能通过调用操作系统提供的系统调用接口,我们使用的fopen,fwrite,fclose等等接口底层也是调用系统调用接口
而系统调用接口只有一套,语言有无数种,每一种又不一样,那么我们学习文件操作只需要学习操作系统提供的系统调用中有关文件操作的接口即可,学习了系统调用就相当于学习了底层,以后我们再学习语言的文件操作时只需要学习一些新的方式即可,但是底层是不变的,这样就会大大降低学习的成本
1.C语言文件操作
在学习C语言的文件操作之前,我们先回顾一下C语言的操作函数
C语言文件操作接口
| 函数名 | 函数功能 |
|---|---|
| fopen | 打开指定文件 |
| fclose | 关闭指定文件 |
| fwrite | 以二进制的形式向文件中写入数据 |
| fread | 以二进制的形式从文件中读取数据 |
| fscanf | 把文件中的数据格式化的读取到内存中 |
| fprintf | 把内存中的数据格式化的写入到文件中 |
总结:
-
fopen:用于打开文件,并返回一个文件指针,可以指定不同的打开模式(如只读、只写、追加等)和文件类型(文本或二进制)。配合其他文件操作函数使用,如fprintf、fscanf等。 -
fclose:用于关闭文件,关闭后文件指针指向的文件将不可访问。 -
fread:从文件中读取数据到指定的内存缓冲区中,可以指定要读取的数据块的大小和数量。 -
fwrite:将指定大小的数据块从内存缓冲区写入文件中,可以指定要写入的数据块的大小和数量。 -
fseek:设置文件指针的位置,用于定位读写位置。可以通过设置相对于文件开头、文件末尾或当前位置的偏移量来移动文件指针。 -
ftell:获取文件指针的当前位置,返回当前位置的偏移量。 -
rewind:将文件指针重置到文件的起始位置,相当于调用fseek(file, 0, SEEK_SET)。 -
feof:检查文件指针是否已到达文件末尾,返回非零值表示到达文件末尾。 -
fgets:从文件中读取一行数据到指定的字符数组中。 -
fprintf:将格式化的数据写入文件中。
需要注意的是,在使用文件操作接口时,应当检查返回值以确保操作是否成功,并且在不需要使用文件时要及时关闭文件以释放资源。
C语言文件打开的几种方式
| 文件打开方式 | 含义 | 如果指定文件不存在 |
|---|---|---|
| “r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
| “w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
| “a”(追加) | 向文本文件尾部添加数据 | 建立一个新的文件 |
| “rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
| “wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
| “ab”(追加) | 向一个二进制文件尾部添加数据 | 出错 |
| “r+”(读写) | 为了读和写,打开一个文件文件 | 出错 |
| “w+”(读写) | 为了读和写,建立一个新的文件 | 建立一个新的文件 |
| “a+”(读写) | 打开一个文件,在文件的尾部进行读写 | 建立一个新的文件 |
总结:
r(只读):以只读方式打开文件。文件必须存在,否则打开失败。w(只写):以只写方式打开文件。如果文件存在,则文件内容会被截断为空;如果文件不存在,则会创建新文件。a(追加写):以追加写入方式打开文件。如果文件存在,则新的数据会追加到文件末尾;如果文件不存在,则会创建新文件。r+(读写):以读写方式打开文件。文件必须存在,允许读取和写入文件内容。w+(读写,创建新文件):以读写方式打开文件。如果文件存在,则文件内容会被截断为空;如果文件不存在,则会创建新文件。a+(追加读写):以追加读写方式打开文件。如果文件存在,则新的数据会追加到文件末尾;如果文件不存在,则会创建新文件。允许读取和写入文件内容。
需要注意的是,以上文件打开模式只适用于文本文件。对于二进制文件,可以在以上模式后添加b来表示二进制模式(例如rb、wb等)。
此外,还有一些其他的文件打开模式,如rb+、wb+等。这些模式在于读取和写入的组合方式,具体的操作方式和特性与上述模式类似,但会有一些细微的区别。
在选择文件打开模式时,需要根据具体的需求和操作来确定使用哪种模式。例如,如果需要只读取文件内容,则使用r模式;如果需要追加写入内容,则使用a或a+模式;如果需要同时读取和写入文件内容,则使用r+、w+或a+模式,具体选择根据是否需要创建新文件或截断文件内容来决定。
C语言文件操作的例子
1.向文件中写入数据
#include <stdio.h>#define FILE_NAME "log.txt"int main()
{FILE *fp = fopen(FILE_NAME, "w");if (NULL == fp){perror("fopen failed");return 1;}int cnt = 5;while (cnt){fprintf(fp,"%s:%d\n","hello world",cnt--);}fclose(fp);return 0;
}

2.从文件中读取数据
#include <stdio.h>
#include <string.h>
#define FILE_NAME "log.txt"int main()
{FILE *fp = fopen(FILE_NAME, "r");if (NULL == fp){perror("fopen failed");return 1;}char buffer[64];while(fgets(buffer,sizeof (buffer)-1,fp)!=NULL){buffer[strlen(buffer) - 1] = 0;puts(buffer);}fclose(fp);return 0;
}

注意:
1.r(只读),w(只写), r+(读写,不存在出错),w+(读写, 不存在创建), a(append, 追加), a+()
2.以w方式单纯的打开文件,无论是否写入数据,c语言会自动清空内部的数据
3.通过fwrite创建出来的文件log.txt,其权限是664,这是由于普通文件的默认权限为0666,linux默认的umask为0002,而文件的最终权限等于默认权限 & ~umask,所以log.txt的权限为0664

2.操作系统文件操作
2.1 比特位传递选项
C语言常通过一个整形来传递选项,但是当选项较多时,每一个选项都用一个整形来进行传递,那么函数的参数就会很多,这时就提出了使用一个比特位来传递一个选项,这样一个整形有32个比特位,就可以传递32种选项,多个传递时使用 | 运算即可,具体案例如下:
#include <stdio.h>// 每一个宏只占用一个比特位,该比特位为1说明该选项成立,且各个宏的位置不重叠
#define OPTION_ONE (1 << 0)
#define OPTION_TWO (1 << 1)
#define OPTION_TREE (1 << 2)
#define OPTION_FOUR (1 << 3)void show(int flags)
{// flags与上面哪个选项匹配,就执行对应的操作// 按位与的结果为1,说明flags对应的比特位为1if (flags & OPTION_ONE)printf("OPTION_ONE\n");if (flags & OPTION_TWO)printf("OPTION_TWO\n");if (flags & OPTION_TREE)printf("OPTION_TREE\n");if (flags & OPTION_FOUR)printf("OPTION_FOUR\n");
}int main()
{// 主函数中通过传递不同的选项来达到不同的效果show(OPTION_ONE);printf("-----------------------\n");show(OPTION_TWO);printf("-----------------------\n");show(OPTION_ONE | OPTION_TWO);printf("-----------------------\n");show(OPTION_ONE | OPTION_TWO | OPTION_TREE);printf("-----------------------\n");show(OPTION_ONE | OPTION_TWO | OPTION_TREE | OPTION_FOUR);printf("-----------------------\n");return 0;
}

如上,我们将宏与比特位对应,然后在show函数中编写每一个宏对应的功能,之后我们就可以在其他函数中通过调用show函数并传递对应的选项来达到我们想要的结果,并且我们可以通过按位或来实现同时传递几个选项
2.2 文件相关系统调用
open & close
函数功能
open:打开或创建一个文件,
close:关闭一个文件


函数参数
int open(const char* pathname, int flags);
int open(const cahr *pathname, int flags, mode_t mode);
# 头文件:<sys/types.h> <sys/stat.h> <fcntl.h>
# pathname: 文件路径/文件名
# flags: 打开文件时,可以传入多个参数选项,用一个或者多个宏常量进行“或”运算,构成flags(比特位传递选项)
参数:O_RDONLY: 只读打开O_WRONLY: 只写打开O_RDWR : 读,写打开这三个常量,必须指定一个且只能指定一个O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限O_APPEND: 追加写
# mode: 指定创建新文件时文件的默认权限(文件最终权限还要受umask的影响)
# 函数返回值:int:文件打开或创建成功返回文件对应的文件描述符(整形),失败返回-1;int close(int fd);
# 头文件:<unistd.h>
# fd:目标文件对应的文件描述符
# int:函数返回值,关闭成功返回0,关闭失败返回-1;
| 文件打开方式 | -含义 | 如果指定文件不存在 |
|---|---|---|
| O_RDONLY | 以只读形式打开 | 出错 |
| O_WRONLY | 以只写形式打开 | 出错 |
| O_RDWR | 以读写形式打开 | 出错 |
| O_APPEND | 向文本文件尾添加数据 | 出错 |
| O_CREAT | 如果文件不存在,创建新文件 | 建立一个新的文件 |
| O_TRUNC | 打开文件时清空文件中之前的数据 | 出错 |
上述这些宏表示不同的文件打开方式,其底层原理和我们上面讲的 通过比特位传递选项 是一样的,我们可以在调用 open 函数时传递一个或多个宏,来实现不同的文件打开方式。
同时,我们可以通过文件操作的系统调用接口和封装后的C语言文件操作接口还是存在很多细节上的不同的,如下:
C语言以 “w” 的方式打开文件,若文件不存在会自动创建一个新文件,而系统调用目标文件不存在直接报错,除非指定了 O_CREAT 选项;
C语言以 “w” 方式打开文件时会自动清空之前文件中的数据,而系统调用则是逐个字符进行覆盖,并不会提前清空文件中的数据,如果要清空必须指定 O_TRUNC 选项;
需要注意的是,O_CREAT 是一个建议性选项,即当文件存在时我们传递此选项也不会报错;同时,文件不存在创建文件时需要传递 mode 选项来指定新文件的访问权限;
上面这些细节的不同也从侧面印证了C语言文件操作接口是对系统调用接口的封装 – “w” 选项会自动清空旧数据、创建新文件,又比如创建新文件时C语言不用手动传递 mode 选项指定权限等等,这些细节都隐藏在了函数的具体实现中。
write 与 read
函数功能
write:向文件中写数据; read:从文件中读数据;


函数参数
ssize_t write(int fd, const void* buf, size_t count);
# 头文件:<unistd.h>
# fd:目标文件的文件描述符
# buf:要写入数据的来源
# count:要写入数据的字节数
# ssize_t:函数返回值,写入成功返回成功写入的字节数,写入失败返回-1ssize_t read(int fd, void* buf, size_t count);
# 头文件:<unistd.h>
# fd:目标文件的文件描述符
# buf:读取数据存放的位置
# count:要读取数据的字节数
# ssize_t:函数返回值,读取成功返回读取写入的字节数,读到文件末尾返回0,读取失败返回-1
2.3 文件操作接口的使用
操作系统系统调用文件相关接口的使用和C语言文件操作接口的使用总体上是差不多的,只是一些细节上有所不同。
1.向文件中写数据
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>#define FILE_NAME "log.txt"int main()
{// 创建文件并以只写形式打开,并指定文件的默认权限为0666(还受umask的影响)// 同时,我们可以通过umask接口手动设置当前进程的文件掩码,而不使用从父进程继承过来的umaskumask(0000);int fd = open(FILE_NAME, O_WRONLY | O_CREAT, 0666);if (fd < 0){perror("open failed");return 1;}int cnt = 5;char buffer[64];while (cnt){sprintf(buffer, "%s:%d\n", "hello world", cnt--);// 注意:这里strlen求得的长度不用加1,因为字符串以'\0'结尾只是C语言的特性,而文件中并不这样规定write(fd, buffer, strlen(buffer));}close(fd);return 0;
}
注意:
1.建 文件时我们通过 umask 系统调用将 umask 设置为了 0000(第一个0代表八进制),然后将 mode 设置为 0666,所以 文件的最终权限为 默认权限 & ~umask – 0666 & ~0000 = 0666;


2.向文件中写入数据时如果不指定 O_TRUNC 选项,新数据就会逐字节覆盖原数据,所以有时候就会出现下面只覆盖了一部分原数据的情况:

3.C语言中字符串以 ‘\0’ 结尾,但是文件中字符串并不以 ‘\0’ 结尾,所以我们向文件中写入字符串时,count 设置为 strlen(str) 就行,不用把最后面的 ‘\0’ 字符加上,如果加上了就会出现部分乱码:

2.从文件中读数据
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>#define FILE_NAME "log.txt"int main()
{// 创建文件并以只写形式打开,并指定文件的默认权限为0666(还受umask的影响)// 同时,我们可以通过umask接口手动设置当前进程的文件掩码,而不使用从父进程继承过来的umaskumask(0000);int fd = open(FILE_NAME, RD_ONLY, 0666);if (fd < 0){perror("open failed");return 1;}char buffer[1024];ssize_t num = read(fd, buffer, sizeof(buffer) - 1);if (num > 0)buffer[num] = 0; // 0, '\0', NULL -> 0printf("%s", buffer);close(fd);return 0;
}

由于C语言字符串以 ‘\0’ 结尾,而文件中的字符串数据并不包含 ‘\0’,所以这里我们需要预留一个位置,便于在数据量大于等于1024字节这种极端情况下 buffer中仍有空间来放置 ‘\0’。
三、文件描述符fd
1.什么是文件描述符
我们知道,文件操作本质上是进程与被打开文件之间的关系,同时,一个进程可以打开多个文件,且操作系统同时运行着许多个进程;那么操作系统中就一定存在着大量被打开的文件,那这些被打开的文件要不要被操作系统管理起来呢?答案是肯定的。
如何管理呢? 答案是先描述,再组织,即将文件的所有属性都总结到一个结构体中,并为每一个文件都创建一个结构体对象,再用一种数据结构将这些结构体对象组织起来,这样对众多被打开文件的管理就变成了对某一种数据结构的增删查改;Linux 中用于管理文件的内核数据结构叫做 struct file {} 结构体,其中包含了文件的大部分属性。
进程如何知道哪些被打开文件属于它呢?如图:

进程的 task_struct 里面有一个 struct files_struct *files 指针变量,它指向一个属于该进程的数据结构对象 struct files_struct,该对象里面包含了一个指针数组 struct file* fd_array[],即进程的文件描述符表,数组里面的每个元素都是指针,指向一个 struct file 对象,而这个数组的下标就是我们用户得到的文件描述符 fd。
也就是说,进程可以通过进程控制块中的 files 变量找到 files_struct 结构体,再通过 files_struct 中的文件描述符表具体下标中保存的地址找到具体文件的内核数据结构 file,从而实现数据的读取与写入。
总结:现在知道,文件描述符就是从0开始的小整数,当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件,于是就有了 file 结构体,表示一个已经打开的文件对象。而进程执行 open 系统调用,所以必须让进程和文件关联起来,于是每个进程都有一个 *files 指针,指向一张表 files_struct,该表最重要的部分就是包含一个指针数组,数组中每个元素都是一个指向打开文件的指针。所以,本质上,文件描述符就是该数组的下标,因此,只要拿着文件描述符,就可以找到对应的文件。
所以,文件描述符是从0开始的小整数,其本质是文件描述符表中的数组下标。
2.文件描述符的分配规则
我们知道了文件描述符是什么,那么文件描述符是如何进行分配的呢?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>#define FILE_NAME(number) "log.txt"#numberint main()
{int fd1 = open(FILE_NAME(1),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd2 = open(FILE_NAME(2),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd3 = open(FILE_NAME(3),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd4 = open(FILE_NAME(4),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd5 = open(FILE_NAME(5),O_WRONLY | O_CREAT | O_TRUNC,0666);printf("fd1 : %d\n",fd1);printf("fd2 : %d\n",fd2);printf("fd3 : %d\n",fd3);printf("fd4 : %d\n",fd4);printf("fd5 : %d\n",fd5);close(fd1);close(fd2);close(fd3);close(fd4);close(fd5);return 0;
}

注:C语言 # 在宏当中的作用 – 将参数插入到字符串中。
从运行结果可以看到,文件描述符是连续分配且依次增大的,这也很合理,因为文件描述符本质上是数组下标,而连续增长正好是数组下标的特性;但是这里有一个很奇怪的地方 – 文件描述符是从3开始的,那么0、1、2号下标呢?这是由三个默认打开的标准流引起的。
标准输入、标准输出与标准错误流
我们在运行一个程序的时候,操作系统会自动为我们打开三个流 – 标准输入流 stdin、标准输出流 stdout、标准错误流 stderr,它们分别对应键盘文件、显示器文件与显示器文件,其文件描述符分别是 0号、1号和2号,所以我们打开其他文件时 fd 默认是从3号开始分配的。即Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.0,1,2对应的物理设备一般是:键盘,显示器,显示器
#include <stdio.h>int main() {printf("stdin->fd:%d\n", stdin->_fileno);printf("stdout->fd:%d\n", stdout->_fileno);printf("stderr->fd:%d\n", stderr->_fileno);return 0;
}

注:Linux 系统调用 open 接口的返回值是文件描述符 fd,而C语言 fopen 接口的返回值是 FILE*,其中 FILE 是一个结构体类型;我们知道,fopen 底层调用的是 open 接口,而 fopen 又不使用 fd 作为函数返回值,那么 FILE 结构体里面就一定会封装一个变量来表示 fd;gcc 中这个变量是 _fileno;
既然系统默认打开三个文件,那么我们可不可以将其关闭呢?当然可以:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>#define FILE_NAME(number) "log.txt"#numberint main()
{close(0);close(2);int fd1 = open(FILE_NAME(1),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd2 = open(FILE_NAME(2),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd3 = open(FILE_NAME(3),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd4 = open(FILE_NAME(4),O_WRONLY | O_CREAT | O_TRUNC,0666);int fd5 = open(FILE_NAME(5),O_WRONLY | O_CREAT | O_TRUNC,0666);printf("fd1 : %d\n",fd1);printf("fd2 : %d\n",fd2);printf("fd3 : %d\n",fd3);printf("fd4 : %d\n",fd4);printf("fd5 : %d\n",fd5);close(fd1);close(fd2);close(fd3);close(fd4);close(fd5);return 0;
}

可以看到,当0号和2号文件描述符被关闭以后,系统将其分配给了新打开的文件 log.txt1 和 log.txt2。
注:close 关闭文件并不是将 fd 指向的 file 对象释放掉,而仅仅是让当前进程文件描述符表中的对应下标不再指向该 file 对象,因为同一个文件可能会被多个进程访问,特别是父子进程。
(其底层可以采用 f_count **引用计数 **的方式来实现,即当有指向该文件的进程关闭时文件计数减1,有指向该文件的进程打开时文件计数加1,当 f_count 为 0 时操作系统才释放该文件的内核数据结构,即真正意义上的关闭文件)
所以,文件描述符的分配规则是:从小到大依次搜寻,寻找未被使用的最小 fd 作为新打开文件的 fd,即在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符
相关文章:
【Linux】基础IO--文件基础知识/文件操作/文件描述符
文章目录 一、文件相关基础知识二、文件操作1.C语言文件操作2.操作系统文件操作2.1 比特位传递选项2.2 文件相关系统调用2.3 文件操作接口的使用 三、文件描述符fd1.什么是文件描述符2.文件描述符的分配规则 一、文件相关基础知识 我们对文件有如下的认识: 1.文件 …...
Intellij IDEA 的安装和使用以及配置
IDE有很多种,常见的Eclipse、MyEclipse、Intellij IDEA、JBuilder、NetBeans等。但是这些IDE中目前比较火的是Intellij IDEA(以下简称IDEA),被众多Java程序员视为最好用的Java集成开发环境,今天的主题就是IDEA为开发工…...
Zynq-Linux移植学习笔记之67- 国产ZYNQ上通过GPIO模拟MDC/MDIO协议
1、背景介绍 模块上有9个PHY,其中两个PHY通过ZYNQ PS端的MDIO总线连接,其余7个PHY单独通过GPIO进行控制,需要实现GPIO模拟MDC/MDIO协议。 2、vivado工程设计 vivado工程内为每个PHY建立两个GPIO IP核,分别用来代表MDC和MDIO&…...
Zookeeper(一)在WSL单机搭建Zookeeper伪集群
目录 Zookeeper1 启动单个Zookeeper实例1.1 下载Zookeeper安装包并解压1.2 添加环境变量1.3 修改默认配置1.4 新建数据存储目录和日志目录1.5 启动Zookeeper1.6 停止Zookeeper 2 搭建Zookeeper集群2.1 新建集群目录2.2 配置环境变量2.3 创建节点目录2.4 修改配置2.5 创建节点ID…...
QT(18):QString
目录 QStringQTypedArrayDataQTypedArrayDataQLatin1StringQStringLiteral乱码 QStringRef QString QString 存储16位QChar的字符串,其中每个QChar对应一个 UTF-16代码单元。QString 使用(写入时复制copy-on-write)来减少内存使用并避免不必…...
宏工科技通过CMMI三级认证,软件研发能力获国际权威认可
近日,宏工科技子公司湖南宏工软件成功通过CMMI三级认证并正式获得资质证书,斩获全球软件领域最权威的认证之一,标志着宏工科技在软件技术开发、研发管理、项目管理等多方面获得国际权威认证。 CMMI全称是Capability Maturity Model Integrati…...
2次MD5加密——用于分布式对话
用户端 : 指发起请求并与服务器进行交互的终端设备或应用程序。它可以是电脑、智能手机等。 用户端负责发送请求给服务端,并接收和处理服务端返回的响应。 服务端 : 是指提供服务、接收和处理用户端请求的计算机系统或应用程序。 它监听来自用…...
用Java制作简易版的王者荣耀
第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import j…...
android 保活的一种有效的方法
android 保活的一种有效的方法 为什么要保活 说起程序的保活,其实很多人都觉得,要在手机上进行保活,确实是想做一些小动作,其实有些正常的场景也是需要我们进行保活的,这样可以增强我们的用户体验。保活就是使得程序…...
kibana安装
kibana安装下载注意事项 地址:curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.16.3-linux-x86_64.tar.gz 下载后直接解压启动即可 1. 但需要使用非root用户启动 ,root用户启动会报错 2. kibana需要和elasticsearch版本一致 不然…...
LV.12 D19 ADC实验 学习笔记
一、ADC简介 1.1 ADC ADC(Analog to Digital Converter)即模数转换器,指一个能将模拟信号转化为数字信号的电子元件 1.2 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示,当最大输入电压一定时,位数越高,…...
ubuntu配置免密登录vscode
1、配置免密登录 (1)在windows系统cmd下运行命令 ssh-keygen 一路回车,将会在C:\Users\用户名\.ssh目录下生成两个文件:id_rsa和id_rsa.pub。如下图所示。 (2)进入.ssh目录。如果想使用root用户࿰…...
软件工程--面向对象分析用通俗语言20小时爆肝总结!(包含用例图、活动图、类图、时序图......)
面向对象方法分为面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程(OOP),本文详细介绍面向对象分析 本文参考教材:沈备军老师的《软件工程原理》大多图片来源其中 目录 面向对…...
HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙专栏-11】
文章目录 ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化@Observed 类装饰器说明装饰器参数类装饰器的使用@ObjectLink 变量装饰器说明装饰器参数同步类型允许装饰的变量类型被装饰变量的初始值举例装饰器的限制条件观察变化和行为表现观察的变化框架行为使用场景1.…...
网络通信安全的坚固防线双向认证技术详解
目录 什么是双向认证 双向认证的工作原理 双向认证的实现方式 双向认证的重要性 双向认证的挑战 安全最佳实践 小结 什么是双向认证 双向认证,又称为双向身份验证或双向鉴别,是一种在通信双方之间建立信任关系的安全机制。在通信过程中࿰…...
Appium+python+unittest搭建UI自动化框架
阅读本小节,需要读者具备如下前提条件: 1. 掌握一种编程语言基础,如java、python等。 2. 掌握一种单元测试框架,如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架,移动端APP测试框架…...
使用paddledetection的记录
首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录: 目录 数据集准备 配置文件的修改 使用的是BML的平台工具: !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…...
MySQL数据库的备份与恢复
在管理MySQL数据库时,备份和恢复是保证数据安全和完整性的关键环节。本文将指导您如何有效地备份MySQL数据库,并在需要时进行数据恢复。 请注意,如果没有 mysql> 的标志,说明我们是在外面终端进行的操作 创建备份文件路径 在…...
Pycharm配置jupyter使用notebook详细指南(可换行conda环节)
本教程为事后记录,部分图片非实操图片。 详细记录了pycharm配置jupyter的方法,jupyter添加其他conda环境的方法,远程密码调用jupyter的方法,修改jupyter工作目录的方法。 文章目录 一、入门级配置1. Pycharm配置Conda自带的jupyt…...
企业微信ipad版,http协议接口发开,获取客户群列表
版本介绍: HTTP协议接口可以通过该接口实现企业微信的各种功能,使用HTTP协议可以避免使用hook形式的需要开启PC客户端的方式,同时可以实现三端同时在线,不影响PC和手机端的登录状态,调用简单,可以支持几千…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
破解路内监管盲区:免布线低位视频桩重塑停车管理新标准
城市路内停车管理常因行道树遮挡、高位设备盲区等问题,导致车牌识别率低、逃费率高,传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法,正成为破局关键。该设备安装于车位侧方0.5-0.7米高度,直接规避树枝遮…...
