• 【linux】基础IO+系统文件IO+文件描述符分配规则


    自我名言只有努力,才能追逐梦想,只有努力,才不会欺骗自己。在这里插入图片描述
    喜欢的点赞,收藏,关注一下把!在这里插入图片描述

    1.重新谈论文件

    根据前面所学知识,我们也了解一些文件的相关知识:

    1.空文件,也要在磁盘占据空间
    2.文件=文件内容+文件属性
    3.文件操作=对内容+对属性 or 对内容和属性
    4.标定一个文件,必须使用:文件路径+文件名【唯一性】
    5.如果没有指定对应的文件路径,默认是在当前路径(进程当前的路径),进行访问

    6.当我们把fopen,fclose,fwrite,fread接口写完之后,代码编码之后,形成一个二进制可执行程序之后,但是没有运行,文件对应的操作有没有被执行?

    其实并没有,对文件的操作,本质:进程对文件的操作!

    7.一个文件如果没有被打开,可以直接进行文件访问吗?

    不能,一个文件要被访问,必须先被打开。 那么被谁打开呢?

    对文件的操作,是在进程中进行的,因此首先是用户进程,其次对文件操作的C接口是封装了系统调用接口,这部分是由OS操作的。

    因此是由用户进程+OS共同进行的。

    是不是所有文件都被打开呢?

    不是,这里文件分成两类
    a.被打开的文件
    b.没有被打开的文件

    上述这么多知识都是为了阐明一点:
    文件操作的本质:进程+被打开文件的关系

    2.重谈文件操作(C语言)

    1.C,C++,Java,python…shell都有对文件操作的接口,但是接口都不一样

    根据目前掌握的知识,了解文件在磁盘里,而磁盘是一个硬件OS能访问硬件,因此所有人想访问磁盘都绕不过OS使用的是OS提供的接口,想访问的是磁盘上的文件,因此使用的是OS提供文件级别的系统调用接口所有语言访问文件接口五花八门,但是操作系统只有一个。

    所以上层语言无论如何变化
    a.库函数底层都必须调用系统调用接口
    b.库函数可以千变万化,但是底层不变

    为了降低学习成本------->学习不变的东西

    2.1C文件接口

    2.文件的操作(C语言)

    在C的时候学过文件相关操作知识,这里不再详细说,对这块知识记得不清的可以参考这篇博客超详细C语言文件操作,学完对文件了解更进一步

    在这里插入图片描述
    fopen打开文件,必须要提供打开的方式。这里总结一下

    r(读),w(写),
    r+(读写,文件不存在报错),w+(读写,文件不存在创建),
    a(append,追加),a+(在文件尾读写,文件不存在创建),
    rb(读(二进制)),wb(写(二进制)),
    rb+(读写(二进制),报错),wb+(读写(二进制),创建)
    ab(二进制文件尾追加),ab+(二进制文件尾读写,创建)

    在这里插入图片描述

       1 #include<stdio.h>
      2 
      3 int main()
      4 {
      5     //打开
      6     FILE* fp=fopen("log.txt","w");
      7     if(fp == NULL)
      8     {
      9         perror("fopen");
     10         return 1;
     11     }
     12 
     13     //写
     14     int cnt=5;
     15     while(cnt)
     16     {
     17         fprintf(fp,"%s:%d\n","hello linux",cnt--);
     18     }
     19 
     20     //关闭                                                                                                                                                       
     21     fclose(fp);          
     22     return 0;            
     23 }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

      1 #include<stdio.h>
      2 #include<string.h>
      3 
      4 int main()
      5 {
      6     //打开
      7    // FILE* fp=fopen("log.txt","w");
      8     FILE* fp=fopen("log.txt","r");
      9     if(fp == NULL)
     10     {
     11         perror("fopen");
     12         return 1;
     13     }
     14 
     15    // //写
     16    // int cnt=5;
     17    // while(cnt)
     18    // {
     19    //     fprintf(fp,"%s:%d\n","hello linux",cnt--);
     20    // }
     21 
     22    //读
     23     char buffer[64];
     24     while(fgets(buffer,sizeof(buffer)-1,fp) !=  NULL)
     25     {
     26         buffer[strlen(buffer)-1]=0;
     27         puts(buffer);                                                                                                                                            
     28     }
     29 
     30     //关闭
     31     fclose(fp);
     32     return 0;
     33 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述
    追加

      1 #include<stdio.h>
      2 #include<string.h>
      3 
      4 int main()
      5 {
      6     //打开
      7    // FILE* fp=fopen("log.txt","w");
      8    // FILE* fp=fopen("log.txt","r");
      9     FILE* fp=fopen("log.txt","a");
     10     if(fp == NULL)
     11     {
     12         perror("fopen");
     13         return 1;
     14     }
     15 
     16    //写                                                                                                                                                          
     17    int cnt=5;
     18    while(cnt)
     19    {
     20        fprintf(fp,"%s:%d\n","hello linux",cnt--);
     21    }
     22 
     23   // //读
     24   //  char buffer[64];
     25   //  while(fgets(buffer,sizeof(buffer)-1,fp) !=  NULL)
     26   //  {
     27   //      buffer[strlen(buffer)-1]=0;
     28   //      puts(buffer);
     29   //  }
     30 
     31     //关闭
     32     fclose(fp);
     33     return 0;
     34 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述
    以w方式单词的打开文件,C会自动清空内部数据

      1 #include<stdio.h>
      2 #include<string.h>
      3 
      4 int main()
      5 {
      6     //打开
      7     FILE* fp=fopen("log.txt","w");
      8    // FILE* fp=fopen("log.txt","r");
      9    // FILE* fp=fopen("log.txt","a");
     10     if(fp == NULL)
     11     {
     12         perror("fopen");
     13         return 1;
     14     }                  
     15                        
     16  //  //写
     17  //  int cnt=5;        
     18  //  while(cnt)        
     19  //  {                                                                                                                                                           
     20  //      fprintf(fp,"%s:%d\n","hello linux",cnt--);  
     21  //  }                 
     22                        
     23   // //读              
     24   //  char buffer[64];  
     25   //  while(fgets(buffer,sizeof(buffer)-1,fp) !=  NULL)  
     26   //  {                
     27   //      buffer[strlen(buffer)-1]=0;  
     28   //      puts(buffer);  
     29   //  }               
     30                       
     31     //关闭          
     32     fclose(fp);     
     33     return 0;       
     34 } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    这些都是C语言给我提供的一些对文件操作的接口。现在来看看OS给我们提供的关于对文件操作的系统调用的接口。

    3.系统文件IO

    3.1open

    在这里插入图片描述
    open有两个接口,首先来讲第二个接口
    在这里插入图片描述

    第一个参数:文件名
    第三个参数:权限(如果创建一个文件,告诉系统该文件的权限是什么)

    在这里插入图片描述

    第二个参数:flags(是一个标记位,告诉系统以什么方式打开文件)

    在这里插入图片描述

    O_RDONLY(只读),O_WRONLY(只写),O_RDWR(读写)

    flags有很多选项,这些选项是大写的,在我们印象中这样写都是宏。

    C传标记位,一个int表示一个标记位,如果想传多个标记位怎么办呢?难道要传多个int吗?
    显然这样处理不好。
    正确解决方法:一个整数---->32个比特位---->通过比特位传递选项(一个比特位,一个选项,比特位位置不能重复)。

      1 #include<stdio.h>
      2 #include<string.h>
      3 
      4 //每一个宏,对应的数值,只有一个比特位是1,彼此位置不能重叠
      5 #define ONE (1<<0)
      6 #define TWO (1<<1)
      7 #define THERE (1<<2)
      8 #define FOUR (1<<3)
      9 
     10 void show(int flags)
     11 {
     12     if(flags & ONE) printf("one\n");
     13     if(flags & TWO) printf("two\n");
     14     if(flags & THERE) printf("there\n");
     15     if(flags & FOUR) printf("four\n");
     16 }
     17 
     18 int main()
     19 {
     20 
     21     show(ONE);
     22     printf("------------------\n");
     23     show(ONE|TWO);
     24     printf("------------------\n");
     25     show(ONE|TWO|THERE);
     26     printf("------------------\n");
     27     show(ONE|TWO|THERE|FOUR);
     28     printf("------------------\n");
     29  
     30     return 0;
     31 }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在这里插入图片描述

    返回值:文件描述符(成功),-1(失败)

    在这里插入图片描述

      #include    
      #include    
      #include    
      #include    
      #include    
         
      int main()    
      {    
          
          //打开    
          int fd=open("log.txt",O_WRONLY);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }    
          
          //关闭                                                                                                                                                         
    	  close(fd);   
    	  return 0}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    文件不存在,并不会自动创建。

    这是因为我们调用C接口,是对底层的封装,然后让底层帮我们创建,但是现在我们直接用的就是底层,如果不给具体选项,是不会帮我们自动创建的。

     #include    
      #include    
      #include    
      #include    
      #include    
         
      int main()    
      {    
          
          //打开    
          //O_CREAT 创建
          int fd=open("log.txt",O_WRONLY|O_CREAT);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }    
    
          //关闭                                                                                                                                                         
    	  close(fd);   
    	  return 0}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    虽然成功创建了文件,但是这个文件权限和我们用C接口创建文件的权限是不一样的,这个是上面所说的原因一样,现在用的是系统调用接口,需要直接告诉这个文件权限是什么。

     #include    
      #include    
      #include    
      #include    
      #include    
         
      int main()    
      {    
          
          //打开    
          int fd=open("log.txt",O_WRONLY|O_CREAT,0666);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }    
          
          //关闭                                                                                                                                                         
    	  close(fd);   
    	  return 0}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    在这里插入图片描述
    文件不存在,用的是有第三个参数的接口。
    文件存在(已经有了权限),用的是没有第三个参数的接口。

    这里可能有个疑问。我给新创建的文件权限设置是0666,为什么新创建的文件权限权限是0664呢?

    文件最终权限=起始权限(0666)&(~umask(普通用户0002))

    所以新创建的文件权限是0664

    那我们就想新创建的文件权限就是我们设置的权限怎么办呢?

    umask(0)

    清掉系统默认的umask

     #include    
      #include    
      #include    
      #include    
      #include    
         
      int main()    
      {    
          umask(0);
          //打开    
          int fd=open("log.txt",O_WRONLY|O_CREAT,0666);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }    
          
          //关闭                                                                                                                                                         
    	  close(fd);   
    	  return 0}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    我们手动清楚了系统默认的umask,为什么这里还是0002呢?
    在这里插入图片描述
    注意,我们改掉的是子进程的权限,并不影响shell(还是0002)。

    3.2close

    在这里插入图片描述
    关闭文件。
    参数就是文件描述符。

    3.3write

    在这里插入图片描述

    第一个参数:向那个文件里写
    第二个参数:想写对应的缓冲区数据在哪里

    为什么第二个参数用的是void呢?
    语言层面把文件类型分为:1,文本文件 。2,二进制文件。
    但是操作系统一律认为都是二进制文件,所以是void

    第三个参数:缓冲区字节个数

    返回值:成功时,写入内容的字节个数会被返回,失败时返回-1。

    在这里插入图片描述

     #include
      #include
      #include
      #include
      #include
      #include
      #include
      
      int main()    
      {    
          umask(0);    
          //打开    
          int fd=open("log.txt",O_WRONLY|O_CREAT,0666);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }                                                                                                                                                              
          
          //写    
    	  const char* buffer="hello linux\n"; 
          ssize_t num= write(fd,buffer,strlen(buffer)); //向文件中写入string,strlen(buffer)+1 需要加1吗?  
          //你以\0作为字符串的结尾,是C语言的规定,和我文件有什么关系呢?     
    	  if(num<0)    
          {
              perror("write");
              exit(2);
          }
          
          //关闭
          close(fd);
          return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

     #include
      #include
      #include
      #include
      #include
      #include
      #include
      
      int main()    
      {    
          umask(0);    
          //打开    
          int fd=open("log.txt",O_WRONLY|O_CREAT,0666);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }                                                                                                                                                              
          
          //写    
    	  //const char* buffer="hello linux\n";    
    	  const char* buffer="aaaaaa\n";   
          ssize_t num= write(fd,buffer,strlen(buffer));      
    	  if(num<0)    
          {
              perror("write");
              exit(2);
          }
          
          //关闭
          close(fd);
          return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述
    为什么是这样的结果呢?

    C语言以w方式打开文件,会先清空文件内容再写。
    但是open(“log.txt”,O_WRONLY|O_CREAT,0666);只是直接覆盖,并不会清理。
    这是因为我们少传一个参数O_TRUNC。

     #include
      #include
      #include
      #include
      #include
      #include
      #include
      
      int main()    
      {    
          umask(0);    
          //打开    
          int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    
          if(fd<0)    
          {    
              perror("open");    
              return 1;    
          }                                                                                                                                                              
          
          //写    
    	  //const char* buffer="hello linux\n";    
    	  const char* buffer="aaaaaa\n";   
          ssize_t num= write(fd,buffer,strlen(buffer));      
    	  if(num<0)    
          {
              perror("write");
              exit(2);
          }
          
          //关闭
          close(fd);
          return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    以前我们C接口,fopen,以w/a方法打开文件,就是库里直接帮我们把下面工作做好了。
    在这里插入图片描述

    3.4read

    在这里插入图片描述

    第一个参数:从那个文件中读
    第二个参数:读到那个缓冲区
    第三个参数:读多少个字节
    返回值:成功返回读取字节的个数,失败返回-1

    在这里插入图片描述

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    
    
    int main()        
    {                 
        umask(0);     
        //打开        
       //bin int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    
        int fd=open("log.txt",O_RDONLY);    
        if(fd<0)      
        {             
            perror("open");                                                                                                                                    
            return 1;                                                                                                                                          
        }                                                                                                                                                      
                                                                                                                                                                                                                                                                                                                                
        //读                                                                                                                                                   
       char buffer[1024];
       ssize_t num=read(fd,buffer,sizeof(buffer)-1);                                                                                                    
       if(num > 0) buffer[num-1]=0; //0,\0,NULL--->0,,系统调用接口不管读的是什么类型文件,都会当作二进制处理,这里我们想读的是字符串,因此结尾加个\0      
       puts(buffer);
       //关闭
       close(fd);
       return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    3.5lseek

    重新定位读写文件的偏移量
    在这里插入图片描述
    这个函数和fseek类似,这里不再演示。

    3.6总结

    在这里插入图片描述

    4.如何理解文件

    文件操作的本质:进程和被打开文件的关系。

    进程可以打开多个文件吗?—>可以—>系统中一定会存在大量的被打开的文件 —>被打开打开的文件,要不要被OS管理起来呢?—>要 —> 如何管理?—> 先描述,在组织 —> 操作系统为了管理对应打开的文件,必定要为文件创建对应的内核数据结构标识文件 —>struct _file{ } —>包含了文件大部分属性。

      #include
      #include
      #include
      #include
      #include
      #include
      #include
      #define FILE_NAME(number) "log.txt"#number
    
      int main()
      {
          umask(0);
          //打开
         //int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
         // int fd=open("log.txt",O_RDONLY);
         int fd0=open(FILE_NAME(1),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd1=open(FILE_NAME(2),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd2=open(FILE_NAME(3),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd3=open(FILE_NAME(4),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd4=open(FILE_NAME(5),O_WRONLY|O_CREAT|O_TRUNC,0666);
    
      
          printf("fd0:%d\n",fd0);
          printf("fd1:%d\n",fd1);
          printf("fd2:%d\n",fd2);
          printf("fd3:%d\n",fd3);                                                                                                                                        
          printf("fd4:%d\n",fd4);
      
          close(fd0);
          close(fd1);
          close(fd2);
          close(fd3);
          close(fd4);	
          return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在这里插入图片描述
    文件创建成功,并且返回各自对应的文件描述符。
    但是奇怪的是:

    a.为什么从3开始呢?0,1,2去哪里了?
    b.为什么是连续的小整数呢?—>什么会是连续的小整数呢?—> 猜测可能和数组有关

    这里就不得不提到,C程序默认会打开三个标准输入,标准输出,标准错误。
    在这里插入图片描述
    FILE* fp=fopen();问FILE是什么呢?
    int fd=open(); int 是文件描述符

    我们知道C:fopen…是对底层系统调用接口的封装,而底层用的是文件描述符。

    FILE是一个结构体 ----> 必须有一个字段存放文件描述

    C调用文件函数的接口不仅对系统调用接口的封装,与此同时C语言FILE结构体也封装了操作系统内的文件描述符。

    在这里插入图片描述

     #include
      #include
      #include
      #include
      #include
      #include
      #include
      #define FILE_NAME(number) "log.txt"#number
    
      int main()
      {
         umask(0);
         printf("stdin->fd:%d\n",stdin->_fileno);  
         printf("stdout->fd:%d\n",stdout->_fileno);  
         printf("stderr->fd:%d\n",stderr->_fileno);      
          //打开
         //int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
         // int fd=open("log.txt",O_RDONLY);
         int fd0=open(FILE_NAME(1),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd1=open(FILE_NAME(2),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd2=open(FILE_NAME(3),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd3=open(FILE_NAME(4),O_WRONLY|O_CREAT|O_TRUNC,0666);
         int fd4=open(FILE_NAME(5),O_WRONLY|O_CREAT|O_TRUNC,0666);
    
      
          printf("fd0:%d\n",fd0);
          printf("fd1:%d\n",fd1);
          printf("fd2:%d\n",fd2);
          printf("fd3:%d\n",fd3);                                                                                                                                        
          printf("fd4:%d\n",fd4);
      
          close(fd0);
          close(fd1);
          close(fd2);
          close(fd3);
          close(fd4);	
          return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    文件描述符的本质:就是数组的下标。

    进程与文件直之间对应的关系:进程通过文件描述符来指向文件的。

    5.文件描述符(fd)分配规则

      1 #include<stdio.h>  
      2 #include<string.h>  
      3 #include<sys/types.h>  
      4 #include<sys/stat.h>  
      5 #include<fcntl.h>  
      6 #include<unistd.h>  
      7 #include<stdlib.h>  
      8   
      9 int main()  
     10 {  
     11     umask(0);  
     12     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);  
     13     if(fd == -1)
     14     {
     15         perror("open");
     16         exit(1);                                                                                                                                                 
     17     }                                                                                                
     18     printf("fd:%d\n",fd);                                                                            
     19                                                                                                      
     20     close(fd);                                                                                       
     21                                                                                                      
     22     return 0;                                                                                        
     23 }       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

       1 #include<stdio.h>
      2 #include<string.h>
      3 #include<sys/types.h>
      4 #include<sys/stat.h>
      5 #include<fcntl.h>
      6 #include<unistd.h>
      7 #include<stdlib.h>
      8 
      9 int main()
     10 {
     11     close(0);                                                                                                                                                    
     12     umask(0);
     13     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
     14     if(fd == -1)
     15     {
     16         perror("open");
     17         exit(1);
     18     }
     19     printf("fd:%d\n",fd);
     20 
     21     close(fd);
     22 
     23     return 0;
     24 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<sys/types.h>
      4 #include<sys/stat.h>
      5 #include<fcntl.h>
      6 #include<unistd.h>
      7 #include<stdlib.h>
      8 
      9 int main()
     10 {
     11     close(2);                                                                                                                                                    
     12     umask(0);
     13     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
     14     if(fd == -1)
     15     {
     16         perror("open");
     17         exit(1);
     18     }
     19     printf("fd:%d\n",fd);
     20 
     21     close(fd);
     22 
     23     return 0;
     24 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在这里插入图片描述
    对比三次运行结果,发现每次创建新文件fd都不同,在仔细发现这是由于close(fd)关闭文件,所导致的结果。

    由图来解释上述原因

    在这里插入图片描述
    当我们关闭fd为0的文件,重新打开一个文件的时候,进程扫描文件描述符表:从小到大,按照循序寻找最小的且没有被占用的fd。(fd的分配规则)

     1 #include<stdio.h>
      2 #include<string.h>
      3 #include<sys/types.h>
      4 #include<sys/stat.h>
      5 #include<fcntl.h>
      6 #include<unistd.h>
      7 #include<stdlib.h>
      8 
      9 int main()
     10 {
     11    // close(0);
     12    // close(2);
     13     close(1);                                                                                                                                                    
     14     umask(0);                                                         
     15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);             
     16     if(fd == -1)                                                      
     17     {                                                                 
     18         perror("open");                                               
     19         exit(1);                                                      
     20     }                                                                 
     21     printf("fd:%d\n",fd);                                             
     22                                                                       
     23     close(fd);                                                        
     24                                                                       
     25     return 0;                                                         
     26 }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    close(1),为什么没有打印新建文件fd呢?

    printf(“%d\n”,fd); printf会把内容打印到stdout文件中。
    但是close(1)关闭标准输出stdout—>显示器,int fd=open();新打开的文件fd是1。
    stdout–>fd–>1,虽然我们手动关闭了stdout,但是系统并不知道,还以为fd为1的位置是stdout,但是这个位置现在已经被新打开的文件占用了,所以打印到了新打开的文件里。

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<sys/types.h>
      4 #include<sys/stat.h>
      5 #include<fcntl.h>
      6 #include<unistd.h>
      7 #include<stdlib.h>
      8 
      9 int main()
     10 {
     11    // close(0);
     12    // close(2);
     13     close(1);
     14     umask(0);
     15     int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
     16     if(fd == -1)
     17     {
     18         perror("open");
     19         exit(1);
     20     }
     21     printf("fd:%d\n",fd);
     22     
     23     //这里必须刷新一下,不然log.txt里面没有内容,这里和缓冲区有关,下面讲                                                                                                                  
     24     fflush(stdout);      
     25     close(fd);           
     26                          
     27     return 0;            
     28 } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    本来应该打印到显示器文件中,但是确写到文件里了。------>重定向

    有关重定向问题,下篇博文解释!

  • 相关阅读:
    LeetCode_单调栈_简单_496.下一个更大元素 I
    这应该是Linux用户与用户组最详细的知识了吧!
    金融科技论文D部分
    ESP8266-Arduino编程实例-L9110直流电机驱动
    css动画效果(关键帧)
    R语言使用epiDisplay包的pyramid函数可视化金字塔图、基于已有的汇总数据(表格数据)可视化金字塔图、使用main参数添加自定义标题信息
    Tuxera NTFS2024最新永久版下载和安装
    网络安全——逻辑漏洞之越权漏洞
    Java设计模式之单例设计模式
    Linux 文件权限
  • 原文地址:https://blog.csdn.net/fight_p/article/details/133804670