• 【linux】重定向+缓冲区


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

    1.重定向

      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

    在这里插入图片描述

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

    1.1重定向本质

    在这里插入图片描述

    1.2重定向接口

    在这里插入图片描述
    这个主要介绍dup2函数。

    int dup2(int oldfd, int newfd);
    
    • 1

    在这里插入图片描述
    那怎么使用dup2来实现刚才的效果,把打印到显示器内容,写入到"log.txt"
    在这里插入图片描述
    是上面那样写的,还是下面那样写的,我们分析分析。
    在这里插入图片描述
    画图分析
    在这里插入图片描述
    在这里插入图片描述
    因此正确写法如下
    在这里插入图片描述

      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     //重定向                                                                                                                                                     
     22     dup2(fd,1);                                                                                                               
     23     printf("fd:%d\n",fd);                                                                                                     
     24                                                                                                                               
     25     //这里必须刷新一下,不然log.txt里面没有内容                                                                               
     26     fflush(stdout);                                                                                                           
     27     close(fd);                                                                                                                
     28                                                                                                                               
     29     return 0;                                                                                                                 
     30 }  
    
    • 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

    在这里插入图片描述

    1.3重定向分类

    1.3.1>输出重定向

    上面内容就是输出重定向,把新打开文件的fd重定向到fd为1(默认为显示器)的位置。

    1.3.2>>追加重定向

        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     int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);
       17     if(fd == -1)
       18     {
       19         perror("open");
       20         exit(1);
       21     }
       22     //重定向
       23     dup2(fd,1);
       24     printf("你好\n");
       25     printf("吃了吗\n");                                                                                                                                           
       26                                                                                                                           
       27     //这里必须刷新一下,不然log.txt里面没有内容                                                                           
       28     fflush(stdout);                                                                                                       
       29     close(fd);                                                                                                            
       30                                                                                                                           
       31     return 0;                                                                                                             
       32 } 
    
    • 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

    在这里插入图片描述

    1.3.3<输入重定向

    #include
    #include
    #include
    #include
    #include
    #include
    #include
         
    int main()    
    {    
       // close(0);    
       // close(2);    
       // close(1);    
        umask(0);    
       // int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);    
       // int fd=open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);    
        int fd=open("log.txt",O_RDONLY);    
        if(fd == -1)    
        {      
            perror("open");      
            exit(1);      
        }      
        //输入重定向    
        dup2(fd,0);                                                                                                                                                      
        char outbuffer[64];        
        while(1)                   
        {                          
            printf("<");                                                     
            if(fgets(outbuffer,sizeof(outbuffer),stdin) == NULL) break;      
            printf("%s",outbuffer);                                                                                                                        
        }
        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

    在这里插入图片描述

    2.理解 >, >>, <

    在前面实现过一个自己的shell,现在我们给这个shell增加重定向功能来理解重定向。
    在这里插入图片描述

    //增加一个分割指令和文件名的函数                                                                                                                               
    commandstrtok(lineCommand);
    
    • 1
    • 2

    分割的时候,我们需要知道重定向是什么类型,文件是什么名字,因此增加两个全局变量来记录。

      //重定向类型    
      //第一个为初始重定向     
      #define DEFAULT_REDIR 0    
      #define INPUT_REDIR 1  
      #define OUTPUT_REDIR 2    
      #define ERROR_EDIRR 3    
          
      //重定向类型+文件名    
      int redirType=DEFAULT_REDIR;    
      char* redirFile=NULL;    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    分割函数

      //这里找文件名没有写成函数,而写个宏
     #define trimSpace(start) do{\
          while(isspace(*start)) ++start;\
      }while(0)
      
      void commandstrtok(char* cmd)
      {
          assert(cmd);
          char* start=cmd;
          char* end=cmd+strlen(cmd);
    
          while(start < end)
          {
              if(*start == '<')
              {
                  *start=0;
                  ++start;
                  //这里可能 ls -a -l >      log.txt,
                  trimSpace(start);
                  redirType=INPUT_REDIR;
                  redirFile=start;
                  break;
              }
              else if(*start == '>')                                                                                                                                 
              {                                                                                                                                                      
                  *start=0;                                                                                                                                          
                  ++start;                                                                                                                                           
                  if(*start == '>')                                                                                                                                  
                  {                                                                                                                                                  
                      redirType=APPEND_REDIR;                                                                                                                        
                      ++start;                                                                                                                                       
                  }                                                                                                                                                  
                  else                                                                                                                                               
                  {                                                                                                                                                  
                      redirType=OUTPUT_REDIR;                                                                                                                        
                  }                                                                                                                                                  
                  trimSpace(start);                                                                                                                                  
                  redirFile=start;                                                                                                                                       
                  break;                                                                                                                                             
              }                                                                                                                                                      
              else
              {                                                                                                                                                      
                  ++start;
              }
          }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    因为命令是子进程执行的,真正重定向的功能一定是由子进程来完成的,
    但是如何重定向是父进程要告知给子进程的。

    //创建子进程
    pid_t id = fork();
    assert(id != -1);
    if(id == 0)
    {             
       switch(redirType)
       {
        	case INPUT_REDIR:
             {
                 int fd=open("log.txt",O_RDONLY);
                 if(fd <0)
                  {
                      perror("open");
                      return 1;
                   }
                   //重定向文件已经打开了
                    dup2(fd,0);
               }
               	 break;
               case OUTPUT_REDIR:
               case APPEND_REDIR:
               {
                    umask(0);
                    int flags=O_WRONLY|O_CREAT;
                    if(redirType == OUTPUT_REDIR) flags|=O_CREAT;
                    else flags|=O_APPEND;                                                                                                                     
                    int fd=open("log.txt",flags,0666);
                    if(fd < 0)
                    {
                     	perror("open");
                        return 1;
                     }
                      dup2(fd,1);     
                 }
                   break;
                 default:
                 printf("bug?\n");
                   break;
         }
          //程序替换
          execvp(myargv[0],myargv);
          exit(1);
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    shell完整代码

    问:子进程重定向会影响父进程吗?

    不会
    在这里插入图片描述

    问:指向程序替换的时候,会不会影响曾经进程打开的重定向文件呢?

    不会
    在这里插入图片描述

    3.如何理解linux下一切皆文件

    Linux下一切皆文件,那键盘,显示器,磁盘,网卡等硬件在linux下都是文件吗?
    可以这样说的。
    在这里插入图片描述
    在这里插入图片描述

    站在struct file上层看来,所有的设备和文件,统一都是struct file--------->Linux下一切皆文件。

    在这里插入图片描述

    这里可能有这样一个问题,如果同一个文件被多个指针指向,但是某个进程把这个文件关了,会不会影响其他进程对这个文件的操作呢?

    其实并不会,一个被打开的文件有引用计数
    在这里插入图片描述
    表明有几个指针指向这个文件,这样做是因为一个文件可能被多个指针指向。如果某个进程关闭文件,影响到其他进程,就不能保证进程的独立性。close关闭文件,其实并不是真正关闭文件,只是把引用计数减1,当只有一个指针指向这个文件,close关闭文件才是真正关闭这个文件。

    4.缓冲区

    先看一种现象。

      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     printf("hello printf\n");  
     12     fprintf(stdout,"%s\n","hello fprintf");  
     13   
     14   
     15     const char* output="hello write\n";  
     16     write(1,output,strlen(output));  
     17   
     18                                                                                                                                                                  
     19     return 0;  
     20 }     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

      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     printf("hello printf\n");
     12     fprintf(stdout,"%s\n","hello fprintf");
     13 
     14 
     15     const char* output="hello write\n";
     16     write(1,output,strlen(output));
     17 
     18     fork();                                                                                                                                                      
     19     return 0;                                                                                                                           
     20 }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    对比两张图片,第二段代码补充fork(创建子进程),重定向之后,C接口的函数,被打印了两次,系统调用的接口前面都只是打印了一次。

    这是什么原因?现在只是知道肯定是fork函数有关。
    其实这里也和缓冲区有关。

    4.1理解缓冲区问题

    缓冲区本质就是一段内存!!!

    4.1.1为什么要有缓冲区

    这里讲一个小故事,帮助理解。

    在四川的张三要给远在北京的李四送一个键盘。
    在这里插入图片描述
    张三为了节省时间,选择2;
    现实中快递行业的意义?
    节省发送者的时间。

    进程把数据打包给磁盘,是一个很慢的过程,如果让进程一直等着显然不太好。因此我们也需要一个快速的方式----->缓冲区

    在这里插入图片描述
    缓冲区的意义是什么呢?

    节省进程进行数据IO的时间。

    但是我们在用文件写的接口时,并没有专门拷贝数据啊?(以fwrite为例)

    其实与其理解fwrite是写入到文件的函数,倒不如理解fwrie是拷贝函数,将数据从进程拷贝到"缓冲区"或者“外设”中。

    4.1.2缓冲区刷新策略的问题

    把东西给顺丰之后,那顺丰什么时候发货呢?

    张三第二天在想寄一个鼠标给李四,当走到快递站点发现自己昨天的快递还没有发走,就问快递人员,快递人员说,我们的快递都是用大货车和飞机发送的,就这一个快递不可能马上就发走,等到满足发送件货才发。

    缓冲区的刷新策略:
    在这里插入图片描述
    不同外设IO访问速度是不同的。
    缓冲区结合具体的设备,定制自己的刷新策略。(3策略,2特殊)

    3策略
    a.立即刷新 ----> 无缓冲
    b.行刷新 ----> 行缓存 ----> 显示器 (显示器是给人看的,如果一次给很多信息,人看着不舒服)
    c.缓冲区满 ----> 全缓存 ----> 磁盘文件(显示器除外)

    2特例
    1:用户强制刷新 (fflush)
    2:进程退出 (进程退出要刷新缓冲区)

    4.1.3缓冲区在哪里,指的是什么缓冲区

    C接口打印了两次,系统调用接口打印了一次,这种现象一定和缓冲区有关。
    虽然现在不知道缓冲区在哪里,但是我们知道缓冲区一定不在内核中
    因为C接口底层调用的是系统调用接口,如果缓冲区在内核中,write也应该打印两次。

    那缓冲区到底在哪?

    我们之前谈论的所有缓冲区,都指的是用户级语言层面给我们提供的缓冲区
    还记得C程序默认给我们打开stdin,stdout,stderr都是------->FILE*------>指向FILE结构体,结构体包含-------> fd,其实还包含一个缓冲区

    因此,缓冲区在FILE结构体中。

    所以当我们自己要强制刷新:fflush(文件指针),关闭:fclose(文件指针)传的都是FILE*。因为缓存区在FILE结构体中。

    4.1.4如何解释fork问题

    在这里插入图片描述
    代码结束之前,创建子进程。

    1.我们没有进行>输出重定向,看到了三条信息。

    stdout默认使用的是行刷新,在fork之前,两条C函数已经将数据打印输出到到显示器上,你的FILE内部,进程内部不存在对应的数据了。这时创建子进程,等到子进程,父进程退出的时,都要刷新缓冲区,但是这时缓冲区已经没有内容可以刷新了。因此C函数打印两条信息。

    2.>输入重定向之后,C接口打印两次

    当我们进行>,写入文件就不再是显示器,而是普通文件,采用的刷新策略是全缓存,之前2条C打印函数,虽然带了\n,但是不足与将stdout缓冲区写满,数据并没有被刷新。
    fork的时候,stdout属于父进程,创建子进程紧跟着就是进程退出,谁先退出,一定要进行缓冲区刷新(缓存区刷新---->就是修改)
    这时就有了写时拷贝!! 因此C接口,数据最终会显示两份。

    3.write为什么前后只打印一次

    上面过程都是write无关,write没有FILE,而用的是fd,就没有C提供的缓冲区。

    5.缓冲区该如何理解

    自己写一个简易的缓冲区,来帮助理解"数据刷新策略"+“数据如何缓存”

    5.1myStdio.h

      1 #pragma once  
      2 #include<errno.h> 
      3 #include<stdio.h>      
      4 #include<string.h>      
      5 #include<sys/types.h>      
      6 #include<sys/stat.h>      
      7 #include<fcntl.h>      
      8 #include<unistd.h>      
      9 #include<stdlib.h> 
     10   
     11 #define SIZE 1024    
     12 #define SYNC_NOW 1    
     13 #define SYNC_LINE 2      
     14 #define SYNC_FULL 3     
     15                      
     16 typedef struct _FILE{  
     17     int flags;//刷新方式  
     18     int fileno;  //文件描述符
     19     int capacity;//buffer容量  
     20     int size;//buffer当前使用量  
     21     char buffer[SIZE]; //缓冲区
     22 }_FILE;              
     23   
     24                      
     25 _FILE* _fopen(const char* path_name,const char* mode);  
     26 void _fwrite(const void* ptr,int num,_FILE* fp);                                                                                                                 
     27 void _fclose(_FILE* fp);  
     28 void _fflush(_FILE* fp);  
    
    • 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

    5.2myStdio.c

    5.2.1_fopen

     _FILE* _fopen(const char* path_name,const char* mode)
    {
        assert(path_name);
        int flags=0;
        int defaultmode=0666;
    
        if(strcmp(mode,"r") == 0)
        {
            flags|=O_RDONLY;
        }
        else if(strcmp(mode,"w") == 0)
        {
            flags|=(O_WRONLY|O_CREAT|O_TRUNC);
        }
        else if(strcmp(mode,"a") == 0)
        {
            flags|=(O_WRONLY|O_CREAT|O_APPEND);
        }
    
        
        int fd=0;
    
        if(flags & O_RDONLY)
        {
            fd=open(path_name,flags);
        }
        else
        {
            fd=open(path_name,flags,defaultmode);                                                                                                                        
        }
        if(fd < 0)
        {
            const char*err=strerror(errno);
            write(2,err,strlen(err));
    		return NULL;//这就是为什么创建文件失败,返回NULL
        }
    
        _FILE* fp=(_FILE*)malloc(sizeof(_FILE));
        assert(fp);
    
        fp->flags=SYNC_LINE;
        fp->fileno=fd;
        fp->capacity=SIZE;
        fp->size=0;
        memset(fp->buffer,0,SIZE);
    
        return fp;
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    5.2.2_fwrite

    void _fwrite(const void* ptr,int num,_FILE* fp)                                                                                       
    {                                                                                   
                                                                                                                                                                         
        //写到缓冲区里                                                                                                                  
        memcpy(fp->buffer+fp->size,ptr,num); //这里没有考虑缓冲区溢出问题                                                                                           
        fp->size+=num;                                                                                                                  
                                                                                                                                        
        //判断是否要刷新                                                                                                                
        if(fp->flags & SYNC_NOW)                                                                                                        
        {                                                                                                                               
            write(fp->fileno,fp->buffer,fp->size);                                                                                       
            fp->size=0;//清空缓冲区                                                                                                     
        }                                                                                                                               
        else if(fp->flags & SYNC_LINE)                                                                                                  
        {                                                                                                                               
            if(fp->buffer[fp->size-1] == '\n')  //这里也没有考虑abc\ndef这种形式,如果是这样的可以用for循环                                                                                        
            {                                                                                                                            
                write(fp->fileno,fp->buffer,fp->size);                                                                                       
                fp->size=0;                                                                                                             
            }                                                                                                                           
        }                                                                                                                               
        else if(fp->flags & SYNC_FULL)                                                                                                  
        {                                                                                                                               
            if(fp->size == fp->capacity)                                                                                                
            {                                                                                                                            
                write(fp->fileno,fp->buffer,fp->size);                                                                                       
                fp->size=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

    5.2.3_fflush

    void _fflush(_FILE* fp)                                                                                       
    {                                                                                       
        if(fp->size > 0) write(fp->fileno,fp->buffer,fp->size);                                                                                       
        fsync(fp->fileno); //把数据强制从内核缓冲区刷新到磁盘                                                                                     
        fp->size=0;                                                                                                                                                      
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里引入了内核缓冲区,下面解释。

    5.2.4_fclose

    void _fclose(_FILE* fp)                                                                                       
    {                                                                                       
        _fflush(fp);  
        close(fp->fileno);                                                                                                                                               
    }    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.3main.c

    行刷新

      1 #include"myStdio.h"
      2 
      3 
      4 int main()
      5 {
      6     _FILE* fp=_fopen("log.txt","w");
      7     if(fp == NULL)
      8     {
      9         perror("_fopen");
     10         return 1;
     11     }
     12 
     13     int cnt=10;
     14     const char* msg="hello linux\n";
     15     while(1)
     16     {
     17         _fwrite(msg,strlen(msg),fp);
     18         sleep(1);
     19         printf("count:%d\n",cnt--);
     20         if(cnt == 0) break;
     21     }                                                                       
     22     _fclose(fp);
     23 
     24     return 0;
     25 }
    
    • 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"myStdio.h"
        2 
        3 
        4 int main()
        5 {
        6     _FILE* fp=_fopen("log.txt","w");
        7     if(fp == NULL)
        8     {
        9         perror("_fopen");
       10         return 1;
       11     }
       12 
       13     int cnt=10;
       14     const char* msg="hello linux";
       15     while(1)
       16     {
       17         _fwrite(msg,strlen(msg),fp);
       18         sleep(1);
       19         printf("count:%d\n",cnt--);                                       
       20         if(cnt == 0) break;
       21     }                    
       22     _fclose(fp);         
       23                          
       24     return 0;            
       25 }  
    
    • 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"myStdio.h"
      2 
      3 
      4 int main()
      5 {
      6     _FILE* fp=_fopen("log.txt","w");
      7     if(fp == NULL)
      8     {
      9         perror("_fopen");
     10         return 1;
     11     }
     12 
     13     int cnt=10;
     14     const char* msg="hello linux";
     15     while(1)
     16     {
     17         _fwrite(msg,strlen(msg),fp);
     18         _fflush(fp);                                                        
     19         sleep(1);
     20         printf("count:%d\n",cnt--);
     21         if(cnt == 0) break;
     22     }          
     23     _fclose(fp);
     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

    在这里插入图片描述

    6.缓冲区和OS的关系

    在这里插入图片描述
    这里是由write函数,直接把数据写到磁盘上的文件中吗?
    其实并不是这样的。
    在这里插入图片描述
    在这里插入图片描述
    write并不是直接把缓冲区里的内容刷新到文件中,在打开文件对应的struct file{}结构体中其他有一个方法指针,还有一个指向内核缓冲区的指针,系统会把FILE结构体里面缓冲区内容通过struct file{}找到内核缓冲区,再由write()拷贝到内核缓冲区,然后再由这个内核缓冲区把内容刷新到文件中区,至于如何刷新和用户毫无关系,我们所知道的行刷新等,这是由语言层面所分类的,而内核缓冲区刷新由OS自主决定。

    那么我们该如何证明有这个内核缓冲区呢?
    超级大佬可以证明,这里证明不了,但是我们可以看到接口。
    在这里插入图片描述
    还有一个问题,如果OS突然宕机了会发生什么情况?
    数据肯定会丢失。如果还是按照OS规定的内核缓冲区刷新策略肯定是不行的。
    我们希望可以在用户层就告知OS,内核缓冲区不要再给我缓存了,赶紧把数据刷新到磁盘中。

    这里介绍fsync函数

    在这里插入图片描述
    强制性把该文件对应的内核缓冲区数据持久到磁盘。就是OS不要给我缓存了,赶紧把数据给我更新到磁盘上。

  • 相关阅读:
    CodeForces刷题:Football、Letter、Indian Summer、Codecraft III、Triangular numbers
    Redis〔篇〕
    猿创征文 | 基于H5实现跨文档通信 & websocket
    Vue系列(三)之 基础语法下篇【事件处理,表单综合案例,组件通信】
    使用Hadoop MapReduce分析邮件日志提取 id、状态 和 目标邮箱
    SpringBoot使用Mybatis
    【Oracle】Oracle系列之六--Oracle表分区
    更换内存条需要注意什么
    wordpress添加评论过滤器
    神经网络图像输入零均值化的作用(AlexNet)
  • 原文地址:https://blog.csdn.net/fight_p/article/details/133819670