Linux的IO(初阶)

news2024/11/25 20:20:12

Linux的IO(初阶)

文章目录

  • Linux的IO(初阶)
    • 1.C语言文件IO
      • 1.1 C语言文件的(复习)
      • 1.2 相对路径与绝对路径(复习)
      • 1.3 C语言中文件操作函数(复习)
      • 1.4 C语言文件写入方式(复习)
      • 1.5 三个默认打开的流
      • 1.6 FILE类型的理解
    • 2.Linux系统文件IO
      • 2.1 打开文件的系统接口函数:open
      • 2.2 关闭文件的系统接口函数:close
      • 2.3 写入文件信息的系统接口函数:write
      • 2.4 读取文件信息的系统接口函数:read
    • 3.文件描述符fd
      • 3.1 为什么Linux下一切皆文件
      • 3.2 系统管理文件的原理
      • 3.3 文件操作符fd的分配原则
    • 4.对重定向的理解
      • 4.1 输入重定向的原理(<)
      • 4.2 输出重定向的原理(>)
      • 4.3 对dup2的理解
      • 4.4 对dup2的使用

1.C语言文件IO

1.1 C语言文件的(复习)

文件分为文本文件和二进制文件:

  • 文本文件:在内存中什么样,保存在硬盘时需要转化,需要转化成字符,这个操作需要程序员做
  • 二进制文件:在内存中什么样,在硬盘就什么样

1.2 相对路径与绝对路径(复习)

路径可以分为:绝对路径、相对路径

  1. 绝对路径:指目录下的绝对位置,通常从盘符开始的路径。如:C:\data\images\1.png
  2. 相对路径:从当前文件开始出发找目标文件的过程。如:\images\1.png
  3. Windows目录分隔符:\
  4. Linux目录分隔符:/
  5. 注意:C语言下\是转义字符,一般写出\\,比如:C:\\data\\images\\1.png

1.3 C语言中文件操作函数(复习)

请添加图片描述


1.4 C语言文件写入方式(复习)

请添加图片描述


1.5 三个默认打开的流

都说Linux下一切皆文件,也就是说Linux下的任何东西都可以看作是文件,那么显示器和键盘当然也可以看作是文件。我们能看到显示器上的数据,是因为我们向“显示器文件”写入了数据,电脑能获取到我们敲击键盘时对应的字符,是因为电脑从“键盘文件”读取了数据

那么我们就有以下疑问了:

  • 为什么我们向“显示器文件”写入数据以及从“键盘文件”读取数据前,不需要进行打开“显示器文件”和“键盘文件”的相应操作?

  • 打开文件一定是进程运行的时候打开的,而任何进程在运行的时候都会默认打开三个输入输出流,即``标准输入流、标准输出流以及标准错误流,对应到C语言当中就是stdin、stdout以及stderr`

  • 标准输入流对应的设备就是键盘,标准输出流和标准错误流对应的设备都是显示器

  • 查看man手册我们就可以发现,stdin、stdout以及stderr这三个家伙实际上都是FILE*类型的,FILE本质就是一个结构体

extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
  • 当我们的C程序被运行起来时,操作系统就会默认使用C语言的相关接口将这三个输入输出流打开,之后我们才能调用类似于scanf和printf之类的函数向键盘和显示器进行相应的输入输出操作
    请添加图片描述

  • 也就是说,stdin、stdout以及stderr与我们打开某一文件时获取到的文件指针是同一个概念,试想我们使用fputs函数时,将其第二个参数设置为stdout,此时fputs函数会不会之间将数据显示到显示器上呢?

#include <stdio.h>
int main()
{
	fputs("hello stdin\n", stdout);
	fputs("hello stdout\n", stdout);
	fputs("hello stderr\n", stdout);
	return 0;
}

请添加图片描述

  • 答案是肯定的,此时我们相当于使用fputs函数向“显示器文件”写入数据,也就是显示到显示器上
  • 注意: 不止是C语言当中有标准输入流、标准输出流和标准错误流,C++当中也有对应的cin、cout和cerr,其他所有语言当中都有类似的概念。实际上这种特性并不是某种语言所特有的,而是由操作系统所支持的

1.6 FILE类型的理解

请添加图片描述

一些问题的理解:

  1. 外设不止一种,OS该怎么去管理这么多的文件?
    • 先描述再组织。用struct file描述后操作系统再进行组织管理即可
  2. 每个外设的读写方式都不同,用同一种类型(file)该怎样去让他们调用自己的读写呢?
    • 提供不同的方法即可。C里面则是以函数指针的形式体现【这种结构体中写方法的形式】,如下图:
      请添加图片描述
  3. 语言上的接口不过是对系统接口的封装,为什么语言不直接调用系统接口?
    • 语言为了保证自身生态的完整性,肯定不会去直接调用系统接口,而且直接调用的话不具备可移植性。 比如我在windows系统下调用windows的接口,在linux下肯定就行不通了。但是如果我对其进行封装,比如fopen这个函数,在linux下就调用linux系统给的接口,windows下就调用windows系统的接口
    • 同一个头文件不同平台下的实现可能不同

2.Linux系统文件IO

2.1 打开文件的系统接口函数:open

系统接口中使用open函数打开文件,open函数的函数原型如下:

请添加图片描述

int open(const char *pathname, int flags, mode_t mode);

下面我们对open函数的每个参数和返回值进行解析:

  1. open的第一个参数:pathname

    • open函数的第一个参数是pathname,表示要打开或创建的目标文件
    • 若pathname以路径的方式给出,则当需要创建该文件时,就在pathname路径下进行创建
    • 若pathname以文件名的方式给出,则当需要创建该文件时,默认在当前路径下进行创建

  2. open的第二个参数:flags

    • open函数的第二个参数是flags,表示打开文件的方式

    • 其中常用选项有如下几个:

请添加图片描述

  • 打开文件时,可以传入多个参数选项,当有多个选项传入时,将这些选项用“或(|)”运算符隔开

  • 例如,若想以只写的方式打开文件,但当目标文件不存在时自动创建文件,则第二个参数设置如下:

    O_WRONLY | O_CREAT
    
  • flags参数是整型,有32比特位,若将一个比特位作为一个标志位,则理论上flags可以传递32种不同的标志位

  • 实际上传入flags的每一个选项在系统当中都是以宏的方式进行定义的:

请添加图片描述

  • 例如,O_RDONLYO_WRONLYO_RDWRO_CREAT在系统当中的宏定义如下:

    #define O_RDONLY         00
    #define O_WRONLY         01
    #define O_RDWR           02
    #define O_CREAT        0100
    
  • 这些宏定义选项的共同点就是,它们的二进制序列当中有且只有一个比特位是1(O_RDONLY选项的二进制序列为全0,表示O_RDONLY选项为默认选项),且为1的比特位是各不相同的,这样一来,在open函数内部就可以通过使用“与”运算来判断是否设置了某一选项


  1. open的第三个参数:mode

    • open函数的第三个参数是mode,表示创建文件的默认权限

    • 例如,将mode设置为0666,则文件创建出来的权限为:-rw-rw-rw-

    • 但实际上创建出来文件的权限值还会受到umask(文件默认掩码)的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,当我们设置mode值为0666时实际创建出来文件的权限为0664,即:-rw-rw-r–

    • 若想创建出来文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0

      umask(0); //将文件默认掩码设置为0
      
    • 当不需要创建文件时,open的第三个参数可以不必设置


  2. open的返回值:

请添加图片描述

  • open函数的返回值是新打开文件的文件描述符

  • 我们可以尝试一次打开多个文件,然后分别打印它们的文件描述符:

    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <fcntl.h>
    int main()
    {
    	umask(0);
    	int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);
    	int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);
    	int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);
    	int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);
    	int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 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);
    	return 0;
    }
    

    运行程序后可以看到,打开文件的文件描述符是从3开始连续且递增的

请添加图片描述

  • 我们再尝试打开一个根本不存在的文件,也就是open函数打开文件失败:

    #include <stdio.h>                                                                                       
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main()
    {
        int fd = open("test.txt", O_RDONLY);
        printf("%d\n", fd);
        return 0;
    }
    

    运行程序后可以看到,打开文件失败时获取到的文件描述符是-1

请添加图片描述

  • 实际上这里所谓的文件描述符本质上是一个指针数组的下标,指针数组当中的每一个指针都指向一个被打开文件的文件信息,通过对应文件的文件描述符就可以找到对应的文件信息

  • 当使用open函数打开文件成功时数组当中的指针个数增加,然后将该指针在数组当中的下标进行返回,而当文件打开失败时直接返回-1,因此,成功打开多个文件时所获得的文件描述符就是连续且递增的

  • 而Linux进程默认情况下会有3个缺省打开的文件描述符,分别就是标准输入0、标准输出1、标准错误2,这就是为什么成功打开文件时所得到的文件描述符是从3开始进程分配的


2.2 关闭文件的系统接口函数:close

系统接口中使用close函数关闭文件,close函数的函数原型如下:

请添加图片描述

int close(int fd);

使用close函数时传入需要关闭文件的文件描述符即可,若关闭文件成功则返回0,若关闭文件失败则返回-1


2.3 写入文件信息的系统接口函数:write

系统接口中使用write函数向文件写入信息,write函数的函数原型如下:

请添加图片描述

ssize_t write(int fd, const void *buf, size_t count);

我们可以使用write函数,将buf位置开始向后count字节的数据写入文件描述符为fd的文件当中:

  • 如果数据写入成功,实际写入数据的字节个数被返回
  • 如果数据写入失败,-1被返回

举例代码:

//运行程序后,在当前路径下就会生成对应文件,文件当中就是我们写入的内容
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0){
		perror("open");
		return 1;
	}
	const char* msg = "hello syscall\n";
	for (int i = 0; i < 5; i++){
		write(fd, msg, strlen(msg));
	}
	close(fd);
	return 0;
}

请添加图片描述


2.4 读取文件信息的系统接口函数:read

系统接口中使用read函数从文件读取信息,read函数的函数原型如下:

请添加图片描述

ssize_t read(int fd, void *buf, size_t count);

我们可以使用read函数,从文件描述符为fd的文件读取count字节的数据到buf位置当中:

  • 如果数据读取成功,实际读取数据的字节个数被返回
  • 如果数据读取失败,-1被返回

举例代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	int fd = open("log.txt", O_RDONLY);
    if (fd < 0){
		perror("open");
		return 1;
	}
	char ch;
	while (1){
		ssize_t s = read(fd, &ch, 1);
		if (s <= 0){
			break;
		}
		write(1, &ch, 1); //向文件描述符为1的文件写入数据,即向显示器写入数据
	}
	close(fd);
	return 0;
}

运行程序后,就会将我们刚才写入文件的内容读取出来,并打印在显示器上,如下图:

请添加图片描述


3.文件描述符fd

3.1 为什么Linux下一切皆文件

每一个硬件都会对应一个struct_file,都会有对应不同访问的方法。 OS看到的时虚拟层,都是一个个的文件(struct_file),如下图:

请添加图片描述


3.2 系统管理文件的原理

我们如果想了解文件描述符的含义,首先我们得知道系统时如何管理文件的!

让我们来思考下以下问题:

  1. 系统为什么要管理文件?

    • 文件是由进程打开的,一个进程可以打开多个文件。理论上来说,多个进程可以打开一个文件,但是这样会导致文件内容混乱,一般不这样做。所以我们可以理解进程和文件的关系为1对多的关系
    • 系统中会有很多进程,也可能会打开很多的文件,为了使文件不会再系统中出现混乱,所以需要系统管理文件

  2. 系统如何管理文件?

    • 先描述和组织
    • 描述文件:Linux操作系统是由C语言编写的,所以操作系统描述文件是通过结构体来描述文件的。这个结构体名字为struct_file
    • 组织文件:系统用一种数据结构,将描述的文件链接起来。用链表,将每一个struct_file连接起来
    • 这样的管理方式就像系统对进程的管理方式一样

  3. 文件与进程的关系?

    • 我们知道,当一个程序运行起来时,操作系统会将该程序的代码和数据加载到内存,然后为其创建对应的task_struct、mm_struct、页表等相关的数据结构,并通过页表建立虚拟内存和物理内存之间的映射关系,如下图:

请添加图片描述

  • 而task_struct当中有一个指针,该指针指向一个名为files_struct的结构体,在该结构体当中就有一个名为fd_array的指针数组,该数组的下标就是我们所谓的文件描述符,即:文件描述符fd实际就是files_struct里数组的下标

  • 当进程打开log.txt文件时,我们需要先将该文件从磁盘当中加载到内存,形成对应的struct file,将该struct file连入文件双链表,并将该结构体的首地址填入到fd_array数组当中下标为3的位置,使得fd_array数组中下标为3的指针指向该struct file,最后返回该文件的文件描述符给调用进程即可,如下图:
    请添加图片描述

  • 因此,我们只要有某一文件的文件描述符,就可以找到与该文件相关的文件信息,进而对文件进行一系列输入输出操作


  1. 各个文件结构体的定义方式是什么样的?

    1. task_struct里的files_struct* 指针结构如下:
      请添加图片描述

    2. files_struct里维护的对应关系的数组:

请添加图片描述

  1. 数组类型struct file的定义:

请添加图片描述

  1. file里描述的操作:

请添加图片描述


  1. 什么叫做进程创建的时候会默认打开0、1、2?

    • 0就是标准输入流,对应键盘;1就是标准输出流,对应显示器;2就是标准错误流,也是对应显示器
    • 而键盘和显示器都属于硬件,属于硬件就意味着操作系统能够识别到,当某一进程创建时,操作系统就会根据键盘、显示器、显示器形成各自的struct file,将这3个struct file连入文件双链表当中,并将这3个struct file的地址分别填入fd_array数组下标为0、1、2的位置,至此就默认打开了标准输入流、标准输出流和标准错误流

  2. 磁盘文件与内存文件如何区分?

    • 当文件存储在磁盘当中时,我们将其称之为磁盘文件,而当磁盘文件被加载到内存当中后,我们将加载到内存当中的文件称之为内存文件。磁盘文件和内存文件之间的关系就像程序和进程的关系一样,当程序运行起来后便成了进程,而当磁盘文件加载到内存后便成了内存文件
    • 磁盘文件由两部分构成,分别是文件内容和文件属性。文件内容就是文件当中存储的数据,文件属性就是文件的一些基本信息,例如文件名、文件大小以及文件创建时间等信息都是文件属性,文件属性又被称为元信息
    • 文件加载到内存时,一般先加载文件的属性信息,当需要对文件内容进行读取、输入或输出等操作时,再延后式的加载文件数据

3.3 文件操作符fd的分配原则

结论:文件描述符是从最小但是没有被使用的fd_array数组下标开始进行分配的

验证如下:

比如:尝试连续打开五个文件,看看这五个打开后获取到的文件描述符

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
	umask(0);
	int fd1 = open("log1.txt", O_RDONLY | O_CREAT, 0666);
	int fd2 = open("log2.txt", O_RDONLY | O_CREAT, 0666);
	int fd3 = open("log3.txt", O_RDONLY | O_CREAT, 0666);
	int fd4 = open("log4.txt", O_RDONLY | O_CREAT, 0666);
	int fd5 = open("log5.txt", O_RDONLY | O_CREAT, 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);
	return 0;
}

请添加图片描述

可以看到这五个文件获取到的文件描述符都是从3开始连续递增的,这很好理解,因为文件描述符本质就是数组的下标,而当进程创建时就默认打开了标准输入流、标准输出流和标准错误流,也就是说数组当中下标为0、1、2的位置已经被占用了,所以只能从3开始进行分配

若我们在打开这五个文件前,先关闭文件描述符为0的文件,此后文件描述符的分配又会是怎样的呢?

//同上面代码,不过我们关闭文件描述符为0的文件
close(0);

请添加图片描述

可以看到,第一个打开的文件获取到的文件描述符变成了0,而之后打开文件获取到的文件描述符还是从3开始依次递增的

我们再试试在打开这五个文件前,将文件描述符为0和2的文件都关闭(不要将文件描述符为1的文件关闭,因为这意味着关闭了显示器文件,此时运行程序将不会有任何输出)

close(0);
close(2);

请添加图片描述

最终我们得出结论:文件描述符是从最小但是没有被使用的fd_array数组下标开始进行分配的


4.对重定向的理解

重定向分为:

  • 输入重定向:<
  • 输出重定向:>
  • 追加重定向:>>

重定向的是文件描述符为1的标准输出流


4.1 输入重定向的原理(<)

输入重定向就是,将我们本应该从一个文件读取数据,现在重定向为从另一个文件读取数据

验证过程:

例如,如果我们想让本应该从“键盘文件”读取数据的scanf函数,改为从log.txt文件当中读取数据,那么我们可以在打开log.txt文件之前将文件描述符为0的文件关闭,也就是将“键盘文件”关闭,这样一来,当我们后续打开log.txt文件时所分配到的文件描述符就是0

请添加图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	close(0);
	int fd = open("log.txt", O_RDONLY | O_CREAT, 0666);
	if (fd < 0)
    {
		perror("open");
		return 1;
	}
	char str[40];
	while (scanf("%s", str) != EOF)
    {
		printf("%s\n", str);
	}
	close(fd);
	return 0;
}

请添加图片描述

一点现象:运行结果后,我们发现scanf函数将log.txt文件当中的数据都读取出来了

原因:

  • scanf函数是默认从stdin读取数据的,而stdin指向的FILE结构体中存储的文件描述符是0,因此scanf实际上就是向文件描述符为0的文件读取数据
  • 实际上我们使用重定向时,重定向的是文件描述符为1的标准输出流,而并不会对文件描述符为2的标准错误流进行重定向

4.2 输出重定向的原理(>)

  • 在明确了文件描述符的概念及其分配规则后,现在我们已经具备理解重定向原理的基础了
  • 结论:重定向的本质就是修改文件描述符下标对应的struct file*的内容

验证过程:

输出重定向就是,将我们本应该输出到一个文件的数据重定向输出到另一个文件中

例如,如果我们想让本应该输出到“显示器文件”的数据输出到log.txt文件当中,那么我们可以在打开log.txt文件之前将文件描述符为1的文件关闭,也就是将“显示器文件”关闭,这样一来,当我们后续打开log.txt文件时所分配到的文件描述符就是1,如下图:

请添加图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
	close(1);
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0)
    {
		perror("open");
		return 1;
	}
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	printf("hello world\n");
	fflush(stdout);	
	close(fd);
	return 0;
}

请添加图片描述

一点现象:运行结果后,我们发现显示器上并没有输出数据(printf的),对应数据输出到了log.txt文件当中

原因:

  • printf函数是默认向stdout输出数据的,而stdout指向的是一个struct FILE类型的结构体,该结构体当中有一个存储文件描述符的变量,而stdout指向的FILE结构体中存储的文件描述符就是1,因此printf实际上就是向文件描述符为1的文件输出数据
  • C语言的数据并不是立马写到了内存操作系统里面,而是写到了C语言的缓冲区当中,所以使用printf打印完后需要使用fflush将C语言缓冲区当中的数据刷新到文件中
    请添加图片描述

4.3 对dup2的理解

之前的重定向方法 ,需要先关闭再打开fd,比较麻烦,通常采用dup2实现数据的覆盖达到重定向的目的

要完成重定向我们只需进行fd_array数组当中元素的拷贝即可。例如,我们若是将fd_array[3]当中的内容拷贝到fd_array[1]当中,因为C语言当中的stdout就是向文件描述符为1文件输出数据,那么此时我们就将输出重定向到了文件log.txt

请添加图片描述


4.4 对dup2的使用

函数原型:

请添加图片描述

int dup2(int oldfd, int newfd);

函数功能: dup2会将fd_array[oldfd]的内容拷贝到fd_array[newfd]当中,如果有必要的话我们需要先使用关闭文件描述符为newfd的文件

函数返回值: dup2如果调用成功,返回newfd,否则返回-1

使用dup2时,我们需要注意以下两点:

  • 如果oldfd不是有效的文件描述符,则dup2调用失败,并且此时文件描述符为newfd的文件没有被关闭
  • 如果oldfd是一个有效的文件描述符,但是newfd和oldfd具有相同的值,则dup2不做任何操作,并返回newfd

使用案例:

例如,我们将打开文件log.txt时获取到的文件描述符和1传入dup2函数,那么dup2将会把fd_arrya[fd]的内容拷贝到fd_array[1]中,在代码中我们向stdout输出数据,而stdout是向文件描述符为1的文件输出数据,因此,本应该输出到显示器的数据就会重定向输出到log.txt文件当中

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
	int fd = open("log.txt", O_WRONLY | O_CREAT, 0666);
	if (fd < 0)
    {
		perror("open");
		return 1;
	}
	close(1);
	dup2(fd, 1);
	printf("hello printf\n");
	fprintf(stdout, "hello fprintf\n");
	return 0;
}

请添加图片描述

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

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

相关文章

2023年,学测试还有前途吗?

最近因为疫情等各种原因&#xff0c;大厂裁员&#xff0c;失业等等频频受到关注。 不解释&#xff0c;确实存在&#xff0c;各行各业都很难&#xff0c;但是&#xff0c;说软件测试行业没有前途&#xff0c;我还真不认同&#xff08;不是为培训机构说好话&#xff0c;大环境不…

面向对象编程 上 (1)

目录 学习面向对象内容的三条主线 面向过程与面向对象 面向过程(POP) 与 面向对象(OOP) 面向对象的三大特征 例子&#xff1a;人把大象装进冰箱 面向对象的思想概述 类和对象 面向对象的思想概述 Java类及类的成员 类的语法格式 创建Java自定义类 对象的创建和使用 类…

2022最新的护眼灯怎么选?护眼台灯到底有用吗

众所周知&#xff0c;人眼能看到各种事物&#xff0c;都是由于光线照射到物体身上&#xff0c;然后反射进入人眼成像&#xff0c;但是如果光线不合理或者不合适&#xff0c;那么进入人眼的光线就会对造成巨大的伤害。所以护眼灯到底有没有用&#xff0c;就在于其发出的光线能不…

【python与数据分析】实验十三 北京市空气质量

目录 一、实验内容 二、完成情况 三、数据分析 1.问题描述 2.编程思路 3.程序代码 4.程序运行结果 &#xff08;1&#xff09;2014年-2019年AQI时间序列折线图 &#xff08;2&#xff09;各年AQI折线图、AQI直方图、PM2.5与AQI散点图、空气质量整体情况的饼图 ​&am…

关于虚数与复数

关于虚数与复数1 数的分类1.1 实数域1.2 虚数与复数2 复数的性质及其运算2.1 复平面、大小及辐角2.2 复数四则运算2.3 共轭复数2.4 复数的极坐标表示3 欧拉公式3.1 欧拉公式证明3.2 利用欧拉公式表示极坐标3.3 欧拉公式推导三角函数加法定理4 复数的性质、乘法和除法运算和极坐…

catia基本操作

1.2CATIA的基本操作_哔哩哔哩_bilibili ctrl鼠标中键 视图放大缩小 alt鼠标中键 视图平移 Alt Enter 性质 4、中键可以平移图形 中键和左键&#xff08;或右键&#xff09;可以实现旋转 按下中键&#xff0c;再按右键&#xff0c;放开右键&#xff0c;拖动鼠标&#xff…

【阿里云】阿里云跨账号内网互通

阿里云VPC对等连接提供连通两个VPC的网络连接&#xff0c;您可以使用私有IP地址直接通信&#xff0c;两个VPC就像在同一个网络中一样。您可以与自己同地域或者跨地域其他VPC之间创建对等连接&#xff0c;也可以与其他账号的同地域或者跨地域VPC之间建立对等连接&#xff0c;同地…

PHP基于thinkphp的旅游见闻管理系统#毕业设计

随着旅游行业的不断发展,各家旅游行业之间的竞争日益激烈,旅游部门所需的信息量越来越大,业务操作中涉及的各种线路情况、用户情况以及旅游协作部门的情况越来越复杂多变。而除了一些个别地区已采用了的旅游网站,一般通常是以原始的手工方式处理/新闻资讯。但是工作人员若仅靠手…

JavaEE Spring MVC 常用注解

RequestMapping ⽤来注册接⼝的路由映射。当⽤户访问⼀个 url 时&#xff0c;将⽤户的请求对应到程序中某个类的某个⽅法的过程就叫路由映射。 Controller //类注解不能忘 RequestMapping("/webcontroller") public class WebController {RequestMapping("/say…

CSDNtop1全栈接口测试教程 jmeter接口测试,接口自动化测试【2】

延时等待&#xff08;全局性&#xff09; api 测试⽤例执⾏速度⾮常快&#xff0c;某些时候因为业务的特性想让它延迟⼏秒执⾏&#xff0c;那么这个时候就使⽤延时等待。 参数化 可以理解为&#xff1a;⼀个测试点需要多次操作&#xff0c;并且每次操作数据都是不⼀样但测试步…

机器学习4超参数问题

文章目录一、超参数问题11、超参数&#xff1a;2、如何寻找好的超参数&#xff1f;二、超参数问题2综上所述三、超参数问题3搜索明可夫斯基距离相应的p;更多关于距离的定义&#xff1a;欧拉距离曼哈顿距离进一步推广可以发现其中有一定一致性明可夫斯基距离&#xff1a;&#x…

全网最全(万字整理)_SpringBoot整合ThymeLeaf

文章目录SpringBoot整合Thymeleaf0x01_入门案例0x02_Thymeleaf视图解析简介0x03_Thymeleaf的表达式0x04_Thymeleaf的标签th:textth:eachth:objectth:hrefth:actionth:onclickth:ifth:value0x05_内置对象#dates#Strings#Numbers域对象0x0x_补充一些概念国际化Thymeleaf缓存区重定…

01-09-hive-入门基本概念-hive-mysql安装

01-hive-入门基本概念&#xff1a; 什么是hive hive是基于Hadoop的一个数据仓库工具&#xff0c;用来进行数据提取、转化、加载&#xff0c;这是一种可以存储、查询和分析存储在Hadoop中的大规模数据的机制。hive数据仓库工具能将结构化的数据文件映射为一张数据库表&#xf…

算法竞赛入门【码蹄集进阶塔335题】(MT2271-2275)

算法竞赛入门【码蹄集进阶塔335题】(MT2271-2275&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2271-2275&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2271 完全立方数32. MT2272 质数率3. MT2273 元素共…

如何修复 Windows 11/10上的 0x8007023e Windows 更新错误

修复 0x8007023e 错误 运行 Windows Update 疑难解答重置 Windows Update 组件使用 DISM 工具修复 Windows Update 客户端从 Microsoft update Catalog 网站下载并安装更新运行 Microsoft 支持和恢复助手系统更新根据 Windows 质量更新服务节奏发布到 Windows 设备。如果当您尝…

zookeeper学习(一)zk特性与节点数据类型详解(2022)

Zookeeper是一个开源的分布式协调框架&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。从设计模式角度来理解其实zk是一个基于观察者模式设计的分布式服务管理框架。 CAP理论&#xff1a; cap理论指出对于一个分布式计算系统来说&#xff0c;不可能同时满足以下三…

COMSOL泰森多边形Voronoi图多孔骨架优化模型受力分析

Voronoi模型 在comsol内建立泰森多边形骨架支撑网格&#xff0c;模型采用一般的多边形泰森多边形孔隙以及样条曲边泰森多边形孔隙做对比研究&#xff0c;分析模型在承受压力荷载下的应力分布。通过comsol的固体力学计算可看出拟圆形Voronoi孔隙支撑结构的应力分布更为合理&…

【LIMU-Bert论文阅读】

LIMU-BERT: Unleashing the Potential of Unlabeled Data for IMU Sensing Applications 题目重点&#xff1a; 充分利用无标签数据适用于IMU传感器应用&#xff08;并没有指出specfic task&#xff09; 文章核心&#xff1a; 如何根据IMU数据的特征设计出LIMU-Bert&#xff0c…

基于模糊逼近系统不确项的滑模自适应控制

目录 前言 1.系统描述 2.控制器设计 3.模糊推理估计不确定f 3.1构造模糊系统 3.2模糊推理过程 3.3 自适应律设计 4.仿真分析 4.1仿真模型 4.2仿真结果 5.总结 前言 在一般的建模仿真中&#xff0c;我们假设模型都是可以用数学模型描述出来的是确定的&#xff0c;称…

1. 一些截图方法的比较;2. 将截图直接转换为PDF并拼接,与插入Word后再转换为PDF的对比

1. 一些截图方法的比较 1.1. 有时候当某个软件没有导出功能&#xff0c;或者导出功能受限&#xff0c;比如 tableau public&#xff0c;但又需要获取展示出的可视化信息时&#xff0c;就需要用到截图。如果这些截图还要用在正式文档中&#xff0c;就需要是高清的&#xff0c;至…