【Linux从青铜到王者】第八篇 Linux基础IO

 4	int main()
 5	{
 6	    FILE\* fp=fopen("test.txt","a+");
 7	    if(fp==NULL)
 8	    {
 9	        printf("打开文件失败!\n");
10	        exit(1);
11	    }
12	    char \*arr="bit education!\n";
13	    fwrite(arr,sizeof(char),strlen(arr),fp);
14	    fclose(fp);
15	    return 0;
16	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624135614274.png)


#### 5.fseek移动文件指针


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624143243927.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624142838354.png)


#### 6.ftell获取文件指针当前位置


![在这里插入图片描述](https://img-blog.csdnimg.cn/2021062414325690.png)


#### 7.rewind让文件指针回到文件起始位置


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624143304401.png)


#### 8.fcloes关闭文件


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624142720687.png)


#### 9.输出信息到显示器方法


**fwrite(msg,strlen(msg),sizeof(char),fp);//往log.txt文件里面写**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624144116287.png)



 1	#include<stdio.h>
 2	#include<string.h>
 3	int main()
 4	{
 5	    FILE \*fp=fopen("log.txt","w");
 6	    if(NULL==fp)
 7	    {
 8	        printf("打开文件失败!\n");
 9	    }
10	    else 
11	    {
12	       /\* char c='A';

13 for(;c<‘Z’;c++)
14 {
15 fputc(c,fp);
16 }*/
17 const char* msg=“Hello bit!\n”;
18 // fwrite(msg,strlen(msg),sizeof(char),fp);//往log.txt文件里面写
19 fwrite(msg,strlen(msg),sizeof(char),stdout);//输出,往显示屏上输出
20
21 }
22 fclose(fp);
23 return 0;
24 }


**fwrite(msg,strlen(msg),sizeof(char),stdout);//输出,往显示屏上输出**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624143903869.png)


#### 10.stdin & stdout & stderr


* **C默认会打开三个输入输出流,分别是stdin, stdout, stderr**
* ***仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021062414444799.png)


## 二、系统文件I/O


#### 1.read和write的初次使用


**操作文件,除了上述C接口(当然,C++也有接口,其他语言也有),我们还可以采用系统接口来进行文件访问,先来直接以代码的形式,实现和上面一模一样的代码:**


**写文件**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021062416163175.png)



 1	#include<stdio.h>
 2	#include<stdlib.h>
 3	#include<sys/stat.h>
 4	#include<fcntl.h>
 5	#include<unistd.h>
 6	#include<string.h>
 
 7	int main()
 8	{
 9	   int fd=open("myfile",O_WRONLY|O_CREAT,0644);
10	   if(fd<0)
11	   {
12	       printf("文件打开失败!\n");
13	       exit(1);
14	   }
15	   char\* arr="bit education!";
16	   write(fd,arr,strlen(arr)-1);
17	   close(fd);
18	   return 0;
19	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624151131947.png)  
 **读文件**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624161619295.png)



 1	#include<stdio.h>
 2	#include<stdlib.h>
 3	#include<string.h>
 4	#include<fcntl.h>
 5	#include<sys/stat.h>
 6	#include<unistd.h>
 7	int main()
 8	{
 9	    int fd=open("myfile.txt",O_RDONLY);
10	    if(fd<0)
11	    {
12	        printf("文件打开失败!\n");
13	        exit(1);
14	    }
15	    char\* arr="hello bit!";
16	    char buff[100];
17	    read(fd,buff,strlen(arr)-1);
18	    printf("%s\n",buff);
19	    close(fd);
20	    return 0;
21	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624152520538.png)


#### 2.接口介绍


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624153433953.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)



> 
> **open man open**  
>  #include <sys/types.h>  
>  #include <sys/stat.h>  
>  #include <fcntl.h>  
>  int open(const char \*pathname, int flags);  
>  int open(const char \*pathname, int flags, mode\_t mode);  
>  **pathname:** 要打开或创建的目标文件  
>  **flags:** 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。  
>  **参数:**  
>  O\_RDONLY: 只读打开  
>  O\_WRONLY: 只写打开  
>  O\_RDWR : 读,写打开  
>  这三个常量,必须指定一个且只能指定一个  
>  O\_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限  
>  O\_APPEND: 追加写  
>  **返回值:**  
>  成功:新打开的文件描述符  
>  失败:-1
> 
> 
> 


**mode\_t理解:直接 man 手册,比什么都清楚。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624153527603.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 **open 函数具体使用哪个,和具体应用场景相关,如目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限,否则,使用两个参数的open。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624153555264.png)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624161652584.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


#### 3.open函数返回值


* **在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数**
* **上面的 fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。**
* **而open close read write lseek 都属于系统提供的接口,称之为系统调用接口。**
* **回忆一下我们讲操作系统概念时,画的一张图。**


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624153920139.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 **系统调用接口和库函数的关系,一目了然。所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。**


#### 4.文件描述符fd(file descriptor)


* **通过对open函数的学习,我们知道了文件描述符就是一个小整数。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624171213470.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


#### 5.0 & 1 & 2


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624161453493.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


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



 1	#include<stdio.h>
 2	#include<string.h>
 3	#include<stdlib.h>
 4	#include<fcntl.h>
 5	#include<unistd.h>
 6	int main()
 7	{
 8	    char buff[100];
 9	    int fd=read(0,buff,sizeof(buff));
10	    write(1,buff,strlen(buff)-1);
11	    write(2,buff,strlen(buff)-1);
12	    return 0;
13	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624170455420.png)  
 而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针\*files, 指向一张表files\_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210624170704107.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


#### 6.文件描述符的分配规则


**输出发现fd是3:**



 1	#include<iostream>
 2	#include<fcntl.h>
 3	#include<sys/stat.h>
 4	#include<sys/types.h>
 5	#include<unistd.h>
 6	int main()
 7	{
 8	   int fd=open("myfile",O_RDONLY|O_CREAT);
 9	   if(fd<0)
10	   {
11	       std::cout<<"文件打开失败!"<<std::endl;
12	   }
13	   std::cout<<fd<<std::endl;
14	   close(fd);
15	   return 0;
16	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625104620530.png)  
 **关闭0或者2,在看:**



 1	#include<iostream>
 2	#include<unistd.h>
 3	#include<fcntl.h>
 4	#include<sys/stat.h>
 5	#include<sys/types.h>
 6	int main()
 7	{
 8	    close(0);
 9	   // close(2);
10	    int fd=open("myfile",O_RDONLY|O_CREAT,0664);
11	    if(fd<0)
12	    {
13	        std::cout<<"文件打开失败!"<<std::endl;
14	        return 1;
15	    }
16	    std::cout<<"fd:"<<fd<<std::endl;
17	    close(fd);
18	    return 0;
19	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625104758655.png)  
 **发现是结果是: fd: 0 或者 fd 2 可见,文件描述符的分配规则:在files\_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。**  
 **----------------------最小未分配原则----------------------**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625104918900.png)


#### 7.重定向


##### 1.清空重定向


**我们发现第一次写的hello world被第二次写的你好呀覆盖了,这就是清空重定向。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625124455372.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


##### 2.追加重定向


**我们发现第一次写的hello没有被第二次写的你覆盖,而是追加在hello后面,这就是追加重定向。**![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625124759956.png)


##### 3.重定向本质


**那如果关闭1呢?看代码:**



 1	#include<iostream>
 2	#include<stdlib.h>
 3	#include<unistd.h>
 4	#include<fcntl.h>
 5	#include<sys/types.h>
 6	#include<sys/stat.h>
 7	int main()
 8	{
 9	    close(1);
10	    int fd=open("myfile",O_WRONLY|O_CREAT,0644);
11	    if(fd<0)
12	    {
13	        std::cout<<"文件打开失败!"<<std::endl;
14	        exit(1);
15	    }
16	    std::cout<<"fd:"<<fd<<std::endl;
17	    close(fd);
18	    return 0;
19	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625123853273.png)  
 **此时,我们发现,本来应该输出到显示器上的内容,输出到了文件 myfile 当中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>, >>, <**


* **那重定向的本质是什么呢?**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625124055280.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


#### 8.FILE


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625144330890.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


* **因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的。**
* **所以C库当中的FILE结构体内部,必定封装了fd。**


**来段代码在研究一下:**



 1	#include<iostream>
 2	#include<fcntl.h>
 3	#include<sys/stat.h>
 4	#include<sys/types.h>
 5	#include<string.h>
 6	#include<unistd.h>
 7	#include<stdio.h>
 8	int main()
 9	{
10	    int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0644);
11	    if(fd<0)
12	    {
13	        std::cout<<"文件打开失败!"<<std::endl;
14	        return 1;
15	    }
16	    const char\* str1="hello printf\n";
17	    const char\* str2="hello fwrite\n";
18	    const char\* str3="hello write\n";
19	    write(1,str3,strlen(str3));
20	    printf("%s\n",str1);
21	    fprintf(stdout,"%s\n",str2);
22	    fork();
23	    close(fd);
24	    return 0;
25	
26	
27	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625142805845.png)  
 **但如果对进程实现输出重定向呢? ./hello > file , 我们发现结果变成了:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625143324211.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


* **我们发现 printf 和 fwrite (库函数)都输出了2次,而 write 只输出了一次(系统调用)。为什么呢?肯定和fork有关!**
* **一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲。**
* **printf、fwrite库函数会自带缓冲区(进度条例子就可以说明),当发生重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲。**
* **而我们放在缓冲区中的数据,就不会被立即刷新,甚至fork之后。**
* **但是进程退出之后,会统一刷新,写入文件当中。**
* **但是fork的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。**
* **write 没有变化,说明没有所谓的缓冲。**


**综上: printf、fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区。另外,我们这里所说的缓冲区,都是用户级缓冲区。其实为了提升整机性能,OS也会提供相关内核级缓冲区,不过不再我们讨论范围之内。那这个缓冲区谁提供呢? printf fwrite 是库函数, write 是系统调用,库函数在系统调用的“上层”, 是对系统调用的“封装”,但是 write 没有缓冲区,而 printf fwrite 有,足以说明,该缓冲区是二次加上的,又因为是C,所以由C标准库提供。**


如果有兴趣,可以看看FILE结构体:



> 
> **typedef struct \_IO\_FILE FILE; 在/usr/include/stdio.h**
> 
> 
> 



> 
> 在/usr/include/libio.h  
>  struct \_IO\_FILE {  
>  int \_flags; /\* High-order word is \_IO\_MAGIC; rest is flags. */  
>  #define \_IO\_file\_flags \_flags  
>  //缓冲区相关  
>  /* The following pointers correspond to the C++ streambuf protocol. */  
>  /* Note: Tk uses the \_IO\_read\_ptr and \_IO\_read\_end fields directly. */  
>  char* \_IO\_read\_ptr; /\* Current read pointer */  
>  char* \_IO\_read\_end; /\* End of get area. */  
>  char* \_IO\_read\_base; /\* Start of putback+get area. */  
>  char* \_IO\_write\_base; /\* Start of put area. */  
>  char* \_IO\_write\_ptr; /\* Current put pointer. */  
>  char* \_IO\_write\_end; /\* End of put area. */  
>  char* \_IO\_buf\_base; /\* Start of reserve area. */  
>  char* \_IO\_buf\_end; /\* End of reserve area. */  
>  /* The following fields are used to support backing up and undo. \*/  
>  char *\_IO\_save\_base; /* Pointer to start of non-current get area. \*/  
>  char *\_IO\_backup\_base; /* Pointer to first valid character of backup area \*/  
>  char *\_IO\_save\_end; /* Pointer to end of non-current get area. */  
>  struct \_IO\_marker *\_markers;  
>  struct \_IO\_FILE *\_chain;  
>  **int \_fileno; //封装的文件描述符**  
>  #if 0  
>  int \_blksize;  
>  #else  
>  int \_flags2;  
>  #endif  
>  \_IO\_off\_t \_old\_offset; /* This used to be \_offset but it’s too small. */  
>  #define \_\_HAVE\_COLUMN /* temporary */  
>  /* 1+column number of pbase(); 0 is unknown. */  
>  unsigned short \_cur\_column;  
>  signed char \_vtable\_offset;  
>  char \_shortbuf[1];  
>  /* char* \_save\_gptr; char* \_save\_egptr; \*/  
>  \_IO\_lock\_t \*\_lock;  
>  #ifdef \_IO\_USE\_OLD\_IO\_FILE  
>  };
> 
> 
> 


#### 9.使用 dup2 系统调用


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625144908924.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 **函数原型如下:**



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


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625150048918.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)



 1	#include<iostream>
 2	#include<fcntl.h>
 3	#include<sys/stat.h>
 4	#include<sys/types.h>
 5	#include<string.h>
 6	#include<unistd.h>
 7	#include<stdio.h>
 8	int main()
 9	{
10	    int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0644);
11	    if(fd<0)
12	    {
13	        std::cout<<"文件打开失败!"<<std::endl;
14	        return 1;
15	    }
16	   
17	    dup2(fd,1);
        //close(fd);
18	    const char\* str1="hello printf\n";
19	    const char\* str2="hello fwrite\n";
20	    const char\* str3="hello write\n";
21	    write(1,str3,strlen(str3));
22	    printf("%s\n",str1);
23	    fprintf(stdout,"%s\n",str2);
24	    fflush(stdout);
25	    close(fd);
26	    return 0;
27	
28	
29	}

![在这里插入图片描述](https://img-blog.csdnimg.cn/2021062514523531.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


#### 10.理解文件系统


**我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625170807669.png)


* 每行包含7列:
* **模式**
* **硬链接数**
* **文件所有者**
* **组**
* **大小**
* **最后修改时间**
* **文件名**


**ls -l读取存储在磁盘上的文件信息,然后显示出来**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625171235602.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 **其实这个信息除了通过这种方式来读取,还有一个stat命令能够看到更多信息**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625171325386.png)  
 **上面的执行结果有几个信息需要解释清楚:**


**inode:**  
 **为了能解释清楚inode我们先简单了解一下文件系统:**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625171603109.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625172224276.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


* **Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块(Boot Block)的大小是确定的。**
* **Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子。**
* **超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。**
* **GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下。**
* **块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。**
* **inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。**
* **i节点表:存放文件属性 如 文件大小,所有者,最近修改时间等.。**
* **数据区:存放文件内容。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625172605740.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)  
 **inode编号是有限的,如果要增加inode编号,通过inode table。要找文件,先找文件inode,要找inode,先找inode ID。**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625172901386.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


**将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们通过touch一个新文件来看看如何工作。**



> 
> **[root@localhost linux]# touch abc  
>  [root@localhost linux]# ls -i abc  
>  263466 abc**
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210625173750926.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0OTE4MDkw,size_16,color_FFFFFF,t_70)


* **创建一个新文件主要有一下4个操作:**
* **存储属性:内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。**
* **存储数据:该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。**
* **记录分配情况:文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。**
* **添加文件名到目录。**


**新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。**


#### 11.理解硬链接


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210626132201419.png)


为了做好运维面试路上的助攻手,特整理了上百道 **【运维技术栈面试题集锦】** ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,**小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。**

![](https://img-blog.csdnimg.cn/img_convert/65548fcd8ba98708942e6f2566cd4240.png)

本份面试集锦涵盖了

*   **174 道运维工程师面试题**
*   **128道k8s面试题**
*   **108道shell脚本面试题**
*   **200道Linux面试题**
*   **51道docker面试题**
*   **35道Jenkis面试题**
*   **78道MongoDB面试题**
*   **17道ansible面试题**
*   **60道dubbo面试题**
*   **53道kafka面试**
*   **18道mysql面试题**
*   **40道nginx面试题**
*   **77道redis面试题**
*   **28道zookeeper**

**总计 1000+ 道面试题, 内容 又全含金量又高**

*   **174道运维工程师面试题**

> 1、什么是运维?

> 2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

> 3、现在给你三百台服务器,你怎么对他们进行管理?

> 4、简述raid0 raid1raid5二种工作模式的工作原理及特点

> 5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

> 6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

> 7、Tomcat和Resin有什么区别,工作中你怎么选择?

> 8、什么是中间件?什么是jdk?

> 9、讲述一下Tomcat8005、8009、8080三个端口的含义?

> 10、什么叫CDN?

> 11、什么叫网站灰度发布?

> 12、简述DNS进行域名解析的过程?

> 13、RabbitMQ是什么东西?

> 14、讲一下Keepalived的工作原理?

> 15、讲述一下LVS三种模式的工作过程?

> 16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

> 17、如何重置mysql root密码?

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
百台服务器,你怎么对他们进行管理?

> 4、简述raid0 raid1raid5二种工作模式的工作原理及特点

> 5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

> 6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

> 7、Tomcat和Resin有什么区别,工作中你怎么选择?

> 8、什么是中间件?什么是jdk?

> 9、讲述一下Tomcat8005、8009、8080三个端口的含义?

> 10、什么叫CDN?

> 11、什么叫网站灰度发布?

> 12、简述DNS进行域名解析的过程?

> 13、RabbitMQ是什么东西?

> 14、讲一下Keepalived的工作原理?

> 15、讲述一下LVS三种模式的工作过程?

> 16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

> 17、如何重置mysql root密码?

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值