Linux 基础IO

news2024/10/6 12:23:58

目录

一、复习C文件IO相关操作

示例代码

fopen的打开模式

C标准库默认打开的三个输入输出流

理解当前路径

二、认识文件相关系统调用接口

示例代码

open函数简介

三、文件描述符

初步认识...

文件描述符的本质:

三个默认打开的文件

 文件描述符的分配规则:

四、C库函数和系统调用接口的关系:

五、重定向

输出重定向示例代码

输入重定向示例代码:

重定向的本质:

dup2系统调用

dup2示例代码

dup2示例代码解析

六、缓冲区

缓冲区相关概念:

1. 缓冲区是什么

2. 为什么要有缓冲区?

3. 缓冲区的刷新策略

探究缓冲区的示例代码:

运行结果:

结论:

示例代码的分析:

七、Linux设计哲学:一切皆文件


一、复习C文件IO相关操作

示例代码

  7 int main()                                                                                                                                                                                                   
  8 {
  9     FILE* fp = fopen("log.txt", "w+");
 10     if(fp == NULL)
 11     {
 12         perror("fopen");
 13         return 1;
 14     }
 15     // C output
 16     fprintf(fp, "hello fprintf\n");
 17     fputs("hello fputs\n", fp);
 18     fwrite("hello fwrite\n", strlen("hello fwrite\n"), 1, fp);
 19     fclose(fp);
 20     
 21     fp = fopen("log.txt", "r");
 22     char arr1[64];
 23     char arr2[64];
 24     char arr3[64];
 25     fscanf(fp, "%s", arr1);
 26     fgets(arr2, sizeof(arr2), fp);
 27     fread(arr3, sizeof(arr3), 1, fp);
 28     printf("%s", arr1);
 29     printf("%s", arr2);
 30     printf("%s", arr3);
 31     fclose(fp);
 32     return 0;
 33 }

1. 打开文件fopen,关闭文件fclose,output输出类函数 fwrite fputs fprintf,intput类输入函数fread fscanf fgets

2. 观察可以发现,这里的所有的文件IO的C库函数都和一个FILE*的类型有关,比如fopen的返回值就是一个FILE*类型,剩余所有文件IO类函数都和FILE*有关。

这里的FILE实际上是C标准库在语言层面用来描述一个文件的结构体。

fopen的打开模式

fopen的第二个参数为打开模式,有 r r+ w w+ a a+,不同参数对应不同的打开方式,比如r 为只读,r+为读写;w为写,文件存在则清空内容,不存在则创建,w+为读写,存在则清空,不存在则创建;a为追加模式写,也就是打开文件时会定位到文件末尾,不存在则创建,a+为追加模式读写,不存在则创建;         
这里主要是为了对应后面要学习的文件IO系统接口open,理解库函数和系统调用的关系

C标准库默认打开的三个输入输出流

默认打开的三个输入输出流分别为:标准输入:stdin,标准输出:stdout,标准错误stderr
它们的类型都是FILE*,也就是文件结构体FILE的指针。
这三个文件,所对应的硬件外设分别为键盘,显示器,显示器(一切皆文件)

理解当前路径

FILE *fopen(const char *path, const char *mode);

上方为fopen的函数声明,第一个参数path为你要打开的文件的相对路径或绝对路径。

每一个进程运行起来的时候,都会记录自己当前所在的工作路径,称为cwd

可以理解为,exe为这个进程对应可执行程序的绝对路径,可执行程序名为myfile。而工作路径cwd为这个进程执行起来的时候所处的路径。
如果我们写 fopen("log.txt", "w");   则这里的log.txt 自动转换为 cwd/log.txt   这里和可执行程序所处的位置有关。 

二、认识文件相关系统调用接口

示例代码

int main()
  8 {
  9     // blog,再次使用文件类系统接口
 10     int fd = open("log.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
 11     if(fd < 0)
 12     {
 13         perror("open");
 14         return 1;
 15     }
 16     const char* p = "hello write\n";
 17     write(fd, p, strlen(p));
 18     close(fd);
 19 
 20     fd = open("log.txt", O_RDWR | O_CREAT | O_APPEND, 0666);
 21     char arr[64];
 22     //memset(arr, '\0', sizeof arr);                                                                                                                                                                         
 23     read(fd, arr, sizeof(arr));
 24     printf("%s", arr);
 25     close(fd);
 26     return 0;
 27 }

有关文件IO的系统接口调用,简单学习一下open  write  read close,我们会发现它们和C标准库的文件IO函数相似度非常高,比如 fopen fwrite fread fclose

open函数简介

open函数int open(const char *pathname, int flags, mode_t mode);
第一个参数为要打开的文件的路径,相对路径或绝对路径
第二个参数为标记位,这里是通过宏的方式传递的,比如O_WRONLY 表示只写, O_RDONLY表示只读,O_RDWR表示读写,O_CREAT表示若文件不存在,创建该文件,O_TRUNC表示打开文件时,清空文件....

这里的open函数的第二个参数是以二进制标记位方式传递的,比如 O_RDWR为000001 O_WRONLY为000010,经过|运算符后,为0000011,组成一个int。函数内会根据每一个二进制标记位的01情况判断文件的打开方式

第三个参数为,创建文件时文件的权限设置,比如0666这里为8进制,转换为二进制表示110110110   --    rw-rw-rw-

三、文件描述符

初步认识...

通过文件IO的系统调用接口可以发现,操作系统内核中标识一个进程打开的某一个文件使用的是一个整型int,称为文件描述符 - file descriptor  - fd   我们需要学习的是这个int是如何在操作系统中标识一个文件的。

文件描述符的本质:

1. 进程打开一个文件,需要将文件加载到内存中 -> 文件分为进程打开的内存文件,和没有被任何进程打开的磁盘文件。

2. 每一个进程都可能打开一些文件,所以操作系统中就会有很多内存级文件。那么操作系统就必须管理这些文件。管理就代表着先描述,再组织(类似操作系统管理进程,用PCB描述进程)。而Linux操作系统内核中描述一个被进程打开的文件使用的是 struct file结构体,它会存储文件相关的inode元信息

操作系统中,有很多进程,有很多进程打开的文件。进程和进程打开的每一个文件需要匹配起来。
每一个进程的进程控制块PCB结构体 sturct task_struct中都有一个struct files_struct* flles的结构体指针数据成员
struct files_struct存储的就是这个进程打开的所有文件的各种信息。(Open file table structure)
struct files_struct结构体内有一个struct file* fd_array[] 指针数组。我们知道,操作系统内部描述一个打开的文件就是用的struct file。   
所以,这个数组就是存储着该进程打开的所有内存级文件在操作系统内部的file结构体的地址。而文件描述符fd就是这个数组的下标!

操作系统内核使用int类型的文件描述符来标识该进程打开的每一个文件,实际上这个整型就是一个结构体(struct file)指针数组的下标。来实现进程和进程打开的每一个文件的配对。因此,那些系统调用接口也自然使用文件描述符来标识某一个文件。

拷贝的:而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件

三个默认打开的文件

Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2. 0,1,2对应的物理设备一般是:键盘,显示器,显示器

其实这和C语言默认打开的三个输入输出流是相对应的。那么,是谁配合的谁呢?

 文件描述符的分配规则:

  7 int main()
  8 {
  9     close(0);
 10     int f1 = open("log1.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
 11     int f2 = open("log2.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
 12     int f3 = open("log3.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
 13     int f4 = open("log4.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
 14     printf("%d\n", f1);
 15     printf("%d\n", f2);
 16     printf("%d\n", f3);                                                                                                                                                                                      
 17     printf("%d\n", f4);
 18     close(f1);
 19     close(f2);
 20     close(f3);
 21     close(f4);

我们知道,fd 0 1 2 分别对应的是标准输入 标准输出 标准错误。关闭0号标准输入之后,打开三个文件,发现是0345,所以文件描述符的分配规则为:

在files_struct结构体内部文件指针数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

四、C库函数和系统调用接口的关系:

文件存在磁盘中,磁盘为硬件,要想读写文件,就要向硬件写入

=》 只有操作系统可以通过驱动直接访问管理硬件

=》 操作系统给出了一些系统调用接口,比如文件IO类系统调用接口,open close read write,可以供给读写文件

=》C标准库作为上层语言,要想访问硬件,读写文件,就必须使用操作系统提供的系统调用接口

=》 所以,C库函数实际上就是系统调用接口的封装,比如fopen 封装open fclose封装close... 
比如,fopen("log.txt", w); 封装 open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);

再比如,fopen("log.txt", a); 封装 open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);

=》 操作系统中,描述一个被打开的文件,用的是struct file,而将进程和打开的文件配对起来使用的是文件描述符fd,系统调用接口中也都是用的是文件描述符来标识文件

=》 而C标准库在语言层面描述一个文件使用的是FILE结构体,综上,FILE结构体中一定封装了文件描述符fd

=》 stdout 这个FILE*指向的FILE内就有一个数据成员_fileno,这就是系统调用接口使用的文件描述符fd,在C标准库中定义的FILE结构体内,名为_fileno。

109     fprintf(stdout, "%d\n", stdin->_fileno);      // 0                                                                                                                                                         
110     fprintf(stdout, "%d\n", stdout->_fileno);     // 1
111     fprintf(stdout, "%d\n", stderr->_fileno);     // 2

五、重定向

输出重定向示例代码

   54       close(1);  // 1就是标准输出,stdout->fileno = 1
   55       int fd = open("log.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);  // 写打开,且清空
   56       if(fd < 0)                                                                  
   57       {                  
   58           perror("open");
   59           return 1;      
   60       }                  
   61       // 现在其实fd就是1 
   62       printf("fd:%d\n", fd);
   63       fprintf(stdout, "hello fprintf\n");
   64       fwrite("hahaha\n", strlen("hahaha\n"), 1, stdout);
   65                                                         
   66       // 缓冲区相关                                                                                                                                                                                        
   67       fflush(stdout);
   68       close(fd);
   69       return 0;
   70 }

运行结果:显示器上没有打印内容,数据全部输出到了log.txt内。

代码分析:先把1号文件描述符close了,再打开一个文件时,根据文件描述符的分配规则,选取的是文件描述符表中最小的且没有被占用的下标。所以给log.txt分配的文件描述符就是1

=》 stdout为标准输出,类型为FILE*,而FILE是语言层面的,内部封装的fd为1,这是语言层面没有改变的。此时,在OS内核中的文件描述符表的1号下标处存储的file*已经不是显示器的内存文件的地址了(struct file*),而变为了log.txt对应的内核struct file地址,所以,printf fprintf fwrite都会将数据output到log.txt内。 这就是输出重定向!

同理,如果把O_TRUNC改为O_APPEND,就变为了追加重定向。

输入重定向示例代码:

   10     close(0);
   11     int fd = open("log.txt", O_RDONLY);
   12     char arr[64];
   13     fgets(arr, sizeof(arr), stdin);                                                                                                                                                                        
   14     printf("%s", arr);
   15     close(fd);

此时log.txt的fd = 0,fd=0处存储的是log.txt的内核file地址。

=》 所有本应从标准输入读取的数据,变为了从其他文件中读取,即输入重定向。

重定向的本质:

凡是往原本1号文件描述符对应的标准输出中写的内容,都写到了其他文件中,不再写到标准输出!这就是输出重定向。 

凡是从原本0号文件描述符对应的标准输入读取的内容,变为了从其他文件中读取,即输入重定向。

重定向的本质,其实是在OS内部,更改fd对应的内容的指向。

dup2系统调用

上方利用文件描述符的分配规则,改变0号或1号文件描述符处内容,使其指向其他文件,完成重定向。
事实上,系统调用中有一个dup2系统调用可以更方便地完成这一操作。

#include <unistd.h>
int dup2(int oldfd, int newfd);

//dup2() makes newfd be the copy of oldfd, closing newfd first if necessary, but note the following:

//*  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.

//*  If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.

介绍:dup2是一个系统调用接口,将newfd文件描述符下标处的内容改为oldfd文件描述符下标处内容的拷贝。使newfd和oldfd文件描述符指向同一个文件。(如果newfd处的文件是打开状态,则拷贝之前会先关闭掉newfd处的文件)

dup2示例代码

W>  8 int main(int argc, char* argv[])
    9 {
   10     int fd = open("log.txt", O_CREAT | O_TRUNC | O_WRONLY, 0666);
   11     dup2(fd, 1);
   12     // 此时1和fd处的内容指向同一个文件
   13     printf("fd:%d\n", fd);
   14     printf("test message\n");
   15     int n = 5;
   16     while(n--)
   17     {
   18         fprintf(stderr, "%d\n", n);
   19         sleep(1);
   20     }
   21     close(fd);
   22     fflush(stdout);
   23     sleep(5);
   24     printf("after close\n");
   25     //fflush(stdout);                                                                           

dup2示例代码解析

 这段代码,一方面是使用dup2来演示输出重定向。另一方面是探究两个问题。
1、 1 和 fd都指向同一文件,那么close(fd)之后,文件描述符为1处的文件访问还有效吗?
2.、缓冲区问题

事实证明,fd和1文件描述符指向同一文件,在close(fd)之后,fd = 1处的文件访问依然有效,所以后面的"after close"成功输出到log.txt内。
缓冲区问题:重定向导致刷新策略改变,前两个printf中的\n失效,必须fflush。

若将第一个fflush注释掉,则

 前10s,数据都存储在stdout缓冲区内。最后进程退出强制刷新stdout语言级别缓冲区,使数据刷新到stdout -> fd = 1 -> log.txt文件内。(这里是缓冲区问题,已经不属于上方研究的dup2的范畴了,具体缓冲区问题见下方)

六、缓冲区

缓冲区相关概念:

1. 缓冲区是什么

缓冲区就是一段内存空间

2. 为什么要有缓冲区?

比如用户使用fprintf往文件中输出数据时,实际上需要向磁盘中写入。如果每次fprintf都直接将数据通过操作系统写入到硬件外设内,则会非常慢,原因是内存 与 外设的处理数据速度差距非常大并且与外设预备IO的过程是非常耗时间的,可能是1000倍的差距,导致我们往硬件写入时,需要非常长的处理和响应时间。

因此,我们在内存中设计一段缓冲区,将需要多次与外设IO的数据先暂存在内存的缓冲区内,等待刷新条件达成时,再一次性全部刷新写入到外设中,这样减少了与外设的访问IO次数,则可以提高整机的效率。更重要的是提高用户的响应速度,因为只需要将数据拷贝到内存的另一区域即可!

3. 缓冲区的刷新策略

通常刷新策略分为1. 立即刷新 2. 行刷新(行缓冲)3. 满刷新(全缓冲) 很容易理解的是,全缓冲的效率是最高的,因为意味着最少的外设IO次数,所以,所有的设备文件都倾向于全缓冲。但是,具体的刷新策略需要考量具体的外设使用需求。

通常,显示器的内存文件采用行缓冲(遇到\n则刷新),磁盘文件通常采用全缓冲(缓冲区满了则刷新)。
同时,我们也可以通过fflush强制刷新,或者进程结束时,缓冲区内的数据也会强制刷新。

探究缓冲区的示例代码:

// 示例代码1
 11     printf("hello printf\n");
 12     fprintf(stdout, "hello fprintf\n");
 13     fputs("hello fputs\n", stdout);
 14 
 15     write(1, "hello write\n", strlen("hello write\n"));
 18     fork();                                

// 示例代码2 
  9     int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);
 10     dup2(fd, 1);
 11     printf("hello printf\n");
 12     fprintf(stdout, "hello fprintf\n");
 13     fputs("hello fputs\n", stdout);
 14 
 15     write(1, "hello write\n", strlen("hello write\n"));
 16     
 17     //fflush(stdout);
 18     fork();

// 示例代码3
  9     int fd = open("log.txt", O_WRONLY | O_TRUNC | O_CREAT, 0666);
 10     dup2(fd, 1);
 11     printf("hello printf\n");
 12     fprintf(stdout, "hello fprintf\n");
 13     fputs("hello fputs\n", stdout);
 14 
 15     write(1, "hello write\n", strlen("hello write\n"));
 16     
 17     fflush(stdout);
 18     fork();

运行结果:

示例代码1:显示器中显示全部内容
示例代码2:log.txt文件中C标准库的output函数的输出内容有两份,系统调用接口write函数的输出内容有一份
示例代码3:文件中显示全部内容

结论:

FILE结构体是语言层C标准库提供的,C标准库在每一个FILE结构体内都有一个语言层面的缓冲区(可以简单理解为一个数组,一段内存空间),缓冲区刷新策略由FILE结构体内封装的fd指向的文件类型决定,如果是向显示器写入,则为行缓冲,如果是向磁盘文件写入,则为全缓冲。

操作系统内核中在每一个struct file结构体内都有一个内核级缓冲区,事实上,C标准库IO函数fprintf,fputs,是将数据先存储到FILE结构体内的语言层面缓冲区,等待刷新条件达成或者发生强制刷新,再将数据刷新到OS内核中struct file内的内核级缓冲区中,最终由OS将数据从内核struct file内的缓冲区写入到外设硬件中。(我们不关心内核缓冲区到硬件的刷新,只关心语言层面缓冲区到内核缓冲区的刷新,也就是当C标准库的缓冲区何时刷新)

示例代码的分析:

示例代码1中,stdout的类型为FILE*,指向FILE为标准输出,内部封装了语言层面缓冲区,此时fd = 1对应的外设为显示器,故刷新策略为行缓冲。 printf fprintf fputs将数据刷新到stdout指向的FILE内的缓冲区内,因为此时对应的是显示器,所以为行刷新,于是,当fork时,数据已经刷新到OS内了。 而对于write,这是一个系统调用接口,是直接将数据写入到OS中的,对于write,并没有语言层面的缓冲区。因此,最终所有数据都只有一份,写入到了显示器中。

示例代码2中,由于dup2,使得stdout对应的fd实际指向的文件为磁盘文件,所以,刷新策略由行缓冲变为全缓冲。致使fork前,数据并没有由FILE内的语言层缓冲区刷新到OS内。fork创建子进程,之后,进程结束,会强制刷新缓冲区,此时缓冲区内的数据需要刷新到OS内,清空缓冲区,即一种写操作,故缓冲区内的数据发生写时拷贝,父子进程各一份。最后父子进程都将数据刷新到OS内,所以最终log.txt文件中,C标准库的IO函数的数据有两份。而对于write,是直接将数据写入到OS内的,所以只有一份。

示例代码3中,如果在fork之前,fflush(stdout),则会强制将stdout指向的FILE内的缓冲区数据刷新到OS内(刷新策略外的强制刷新)。所以,在fork创建子进程时,父进程的C标准库的缓冲区内已经没有缓冲数据了(因为已经刷新到log.txt的内核struct file结构体内的缓冲区中了,属于OS,不属于进程),自然不会发生写时拷贝后有两份数据等情况了。


上方缓冲区相关知识,揭示了缓冲区的概念,缓冲区存在的意义,缓冲区的刷新策略,语言层缓冲区和内核级缓冲区。那个示例代码也不是很复杂,只是对不同的文件/设备有不同的刷新策略,当发生重定向时,刷新策略也随之改变,致使数据存留在了语言层,即C标准库提供的缓冲区内,属于进程的数据。再结合fork创建子进程,进程结束时强制刷新缓冲区,以及写时拷贝。就产生了最终现象!

七、Linux设计哲学:一切皆文件

一切皆文件指的是,在操作系统层面,所有的外设硬件,以及磁盘内的文件,都可以看作文件,都可以统一以文件来处理。这是体现在操作系统的软件设计层面的。

如何实现一切皆文件呢?

Linux操作系统是用C语言写的,它要将所有外设都看作统一的文件,就需要以统一的方式来描述和管理。
最好的就是使用结构体,这里可以通过让结构体:struct file内存储一些属性数据,函数指针。从而使用C语言结构体达到面向对象机制和运行时多态。

上方仅是一个简单示例。

我们可以将磁盘,显示器,键盘,网卡,显卡等硬件外设都用这个struct file结构体在操作系统内部描述管理起来。属性数据存储在结构体的数据成员中。而函数指针,可以指向不同外设的具体read write函数实现, 因为底层不同的外设,具体读写方法肯定是不同的,但是我们可以通过函数指针机制,达到在struct file的使用管理层面上,调用读写方法的方式都相同的效果。

这样一来,在操作系统层面来看,硬件之间已经没有任何差别了,都可以统一看作struct file,且可以使用struct file内的函数指针,调用对应外设具体的读写方法。

这就是一切皆文件,这种机制称为VFS,Virtual File System,虚拟文件系统。

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

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

相关文章

SSH客户端工具MobaXterm

前言 SSH客户端远程连接服务器的有xshell(xmanager套件下)&#xff0c;需要收费&#xff0c;也可以通过一些和谐的方式使用。 但是有时候&#xff0c;我们需要使用光明正大的软件SSH到远程服务器&#xff0c;MobaXterm家庭版可以正常的使用。 其他产品&#xff1a; SecureCRT&…

任意代码执行漏洞复现

漏洞简介 在 PostgreSQL 数据库的 jdbc 驱动程序中发现一个安全漏洞。当攻击者控制 jdbc url 或者属性时&#xff0c;使用 PostgreSQL 数据库的系统将受到攻击。 pgjdbc 根据通过 authenticationPluginClassName、sslhostnameverifier、socketFactory 、sslfactory、sslpasswo…

021_SSSS_Diffusion Models Already Have a Semantic Latent Space

Diffusion Models Already Have a Semantic Latent Space 1. Introduction 本文指出&#xff0c;现有的Diffusion模型可以在不同的领域有出色的表现&#xff0c;但是缺少可以控制其生成过程的语义隐空间&#xff08;Semantic Latent Sapce&#xff09;。本文提出了非对称的反…

C++模拟OpenGL库——图片处理及纹理系统(三):图片缩放操作:简单插值二次线性插值

目录 简单插值 二次线性插值 简单插值 如图&#xff0c;我们想把一张小图缩放成一张大图&#xff0c;自然的想法就是按照它们的长宽比例进行缩放&#xff08;zoomX&#xff09;。 但是问题也显而易见&#xff0c;在缩放的过程中&#xff0c;小图的像素并不能一一映射到大图的…

蜂巢能源冲刺科创板上市:拟募资150亿元,上半年收入37亿元

11月18日&#xff0c;蜂巢能源科技股份有限公司&#xff08;下称“蜂巢能源”&#xff09;在上海证券交易所递交招股书&#xff0c;准备在科创板上市。本次冲刺科创板上市&#xff0c;蜂巢能源计划募资150亿元&#xff0c;主要用于动力锂离子电池项目、研发中心建设项目等。 据…

Unity游戏Mod/插件制作教程02 - 开发环境准备

前言 虽然本教程的目标读者是有C#基础的玩家&#xff0c;但是作为流程&#xff0c;基础的开发软件部分我还是要记录一下。 安装VisualStudio VisualStudio是我们开发插件最重要的工具&#xff0c;也许你习惯其他开发.net的工具&#xff0c;但是免费的VisualStudio已经足够好用…

王道OS 1.1_1 操作系统的概念、功能和目标

王道OS 1.1_1 操作系统的概念、功能和目标 chap1 计算机系统概述 参考资料 B站王道考研操作系统概念 第9版 &#xff08;原书、译本&#xff09; 好久没有写博客总结整理和输出了&#xff0c;学习的惰性在一次次的考试周从零开始的经历中达到了巅峰&#xff0c;现在想重振旗鼓…

换工作有感

最近很长一段时间没有更新博客&#xff0c;更新关于vim相关的操作&#xff0c;主要是最近在忙于换工作的事情。其实本来我也没打算换工作的&#xff0c;主要是最近公司的一些骚操作让我觉得心里很不爽&#xff0c;所以一怒之下提出离职。 背景 先来说说这个事情的背景吧&#…

2022年 SecXOps 安全智能分析技术白皮书 附下载地址

近年来&#xff0c;互联网、大数据和人工智能 等技术都得到了飞速的发展&#xff0c;网络攻击的方法也越来越复杂&#xff0c;过去广泛、漫无目的的攻击威胁&#xff0c;在数年内迅速地转化为有目标、有组织、长期 潜伏的多阶段组合式高级可持续威胁&#xff08;Advanced Persi…

计算机网络——第五章网络层笔记(5)

网络地址翻译&#xff08;NAT&#xff09; Private IP address:不可路由的地址、也可用于广域网链路上 NAT&#xff1a;net address translate 私有IP地址和公有IP地址之间的转换。 PAT&#xff1a;port address translate 将多个私有IP地址影射到同一个公有IP地址的不同…

跑步时戴什么耳机好、分享五款最适合跑步的运动耳机排名清单

在进行户外跑步、骑行等运动&#xff0c;往往会感到枯燥乏味&#xff0c;很难坚持下去&#xff0c;就像我经常跑一圈就觉得没了动力&#xff0c;但是当我戴上耳机听音乐跑步时&#xff0c;不知不觉就结束了&#xff0c;就感觉时间过得很快。不过话有说回来&#xff0c;适合跑步…

【JVM】jvm的体系结构

JVM体系结构如下图所示&#xff1a; JVM大致可以分为五大模块&#xff1a; 类加载子系统&#xff08;Class Loader SubSystem&#xff09;运行时数据区&#xff08;Runtime Data Area&#xff09;执行引擎&#xff08;Execution Engine&#xff09;Java本地接口&#xff08;Ja…

Java native关键字 实现

需要用到gcc mingw64: 下载安装MinGW-w64详细步骤&#xff08;c/c的编译器gcc的windows版&#xff0c;win10真实可用&#xff09;_jjxcsdn的博客-CSDN博客_mingw-w64 我也是根据上面地址安装的 在d盘创建一个.java文件 编写内容 testInt方法用 native关键字修饰 静态块里需要…

Tauri 打包

1、第一次打包运行命令 npm run tauri build 2、可能会出现下面问题 我们需要在tauri.conf.json里面查找identifier这个名称 原来是com.tauri.dev 随便改下名字&#xff0c;我这里改成build了 3、修改配置后&#xff0c;继续打包又出现问题&#xff0c;如下图 我们就单独去下…

Google Earth Engine(GEE)——join连接在GEE中的应用(同一sentinel-2影像集合)含滑动窗口平滑影像过程

JOIN联接允许您根据一个或多个条件组合不同的集合。 ImageCollection 到 ImageCollection 在数据融合中很有用(从不同的数据集中找到匹配的图像) FeatureCollection 到 ImageCollection 用于数据提取(在多个位置提取图像) FeatureCollection 到 FeatureCollection 在地理处…

公式编辑器Axmath+公式识别器SimpleTex+Markdown编辑器Typora

Ⅰ.公式编辑器Axmath 下载方式&#xff1a; ①百度网盘&#xff1a;https://pan.baidu.com/share/init?surlUWHIHWJHm-mC5q5LUCyEuA 提取码&#xff1a;1r2a ②城通网盘&#xff1a;https://url86.ctfile.com/f/32005086-727935308-6024d8?p5422 访问码&#xff1a;5422 软件…

Cellular/Wifi/Bluetooth频率

Cellular NR频率 3GPP R17定义的NR FR1频段如下表&#xff1a; 图片来自于38.101国内常用FDD频段&#xff1a; n1: 2100MHz~2170MHz&#xff0c;共79MHz带宽 n3: 1805MHz~1880MHz&#xff0c;共75MHz带宽 n5: 869MHz~894MHz&#xff0c;共25MHz带宽 n8: 925MHz~960MHz&…

【Redis-03】Redis数据库的实现原理

在之前的文章我们介绍过&#xff0c;Redis服务器在启动之初&#xff0c;会初始化RedisServer的实例&#xff0c;在这个实例中存在很多重要的属性结构&#xff0c;同理本篇博客中介绍的数据库实现原理也会和其中的某些属性相关&#xff0c;我们继续看一下吧。 1.服务器和客户端…

基于改进萤火虫算法的图像分割的应用(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

可执行文件的装载与进程

进程虚拟地址空间 每个程序被运行起来以后&#xff0c;它将拥有自己独立虚拟空间地址&#xff0c;这个虚拟地址空间的大学由计算机的硬件平台决定&#xff0c;具体地说是由CPU的位数决定。硬件决定了地址空间的最大理论上限&#xff0c;即硬件的寻址空间大小&#xff0c;比如32…