文件描述符fd

文件描述符

在linux中open函数调用成功后会返回一个非负整数,这个非负整数就是文件描述符。

Linux 默认情况下会缺省打开三个文件描述符 标准输入0 标准输出1 标准错误2

0 1 2 对应的物理设备一般是: 键盘 显示器 显示器

在这里插入图片描述

文件描述符就是从0开始的小整数。当我们打开文件时,操作系统需要创建相应的数据结构来描述目标文件 file结构体 表示一个已经打开的文件对象。当进程执行open系统调用时必需要将文件和进程关联起来。每个进程都有一个指针files指向一张表files_struct* ,该表中有一个指针数组 file* fd_array[] ,这个数组中的每一个元素都指向一个已打开的文件,而文件描述符就是该指针数组的下标

文件描述符的分配规则

在files_struct数组当中,找到没有被使用的最小的一个下标作为文件描述符。

在默认情况下,0 1 2 三个文件描述符是已经打开的,新创建的文件从3开始,当0或1,2有被关闭的从最小的开始

重定向

输出重定向

 #include <stdio.h>                                                               
    2 #include <sys/types.h>                                                           
    3 #include <sys/stat.h>                                                            
    4 #include <stdlib.h>                                                              
    5 #include <fcntl.h>                                                               
    6                                                                                  
    7 int main()                                                                       
    8 {                                                                                
    9   umask(0);                                                                      
   10   close(1);                                                                      
   11   int fd=open("myfile.txt",O_WRONLY|O_CREAT ,0644);                              
   12   if(fd<1)                                                                       
   13   {                                                                              
   14    perror("open");                                                               
   15     return 1;                                                                    
   16   }                                                                              
   17                                                                                  
   18   printf("fd: %d\n",fd);                                                         
   19   fflush(stdout);         //往显示器上刷新缓存区                                                       
   20                                                                                  
   21   close(fd);                                                                     
   22   return 0;                                                                      
   23 }                 
[wens@localhost code2]$ make
gcc -o test test.c
[wens@localhost code2]$ ./test
[wens@localhost code2]$ cat myfile.txt
fd: 1

本来应该输出到屏幕上的内容,输出到了文件myfile.txt中

printf是c库中的io函数,一般往stdout输出,但是stdout底层访问文件时,找的还是fd=1;但是1被关闭后,mefile.txt被创建后,放入了下标为fd=1的位置,所以原本是stdout的位置,此时已将是myfile.txt的位置了,所以输出的消息都输出进了myfile.txt 进而完成输出重定项。

追加重定项:
关掉 1
创建文件时 参数加入追加O_APPEND

输入重定项: 关掉0 创建文件 再从标准输入读取 即完成

FILE


file 结构体是c库提供的文件结构体,其中包含了文件描述符fd,以及自带的缓冲区

1 #include <stdio.h>                                                                 
  2 #include <sys/types.h>                                                             
  3 #include <sys/stat.h>                                                              
  4 #include <stdlib.h>                                                                
  5 #include <fcntl.h>                                                                 
  6 #include <string.h>                                                                
  7 #include <unistd.h>                                                                
  8 int main()                                                                         
  9 {                                                                                  
 10   const char* msg0="printf\n";                                                     
 11   const char* msg1="fwrite\n";                                                     
 12   const char* msg2="write\n";                                                      
 13                                                                                    
 14   printf("%s",msg0);                                                               
 15   fwrite(msg1,1,strlen(msg1),stdout);                                              
 16   write(1,msg2,strlen(msg2));                                                      
 17                                                                                    
 18   fork();                                                                          
 19   return 0;                                                                        
 20 }             

输出结果

wens@localhost code2]$ vim test.c
[wens@localhost code2]$ make
gcc -o test test.c
[wens@localhost code2]$ ./test
printf
fwrite
write
[wens@localhost code2]$ touch file
[wens@localhost code2]$ ./test >file   #对输出进行重定项
[wens@localhost code2]$ cat file
write
printf
fwrite
printf
fwrite
[wens@localhost code2]$ 

缓冲方式

  • 无缓冲:不刷新缓冲区
  • 行缓冲:按行进行刷新
  • 全缓冲:默认情况下只有把缓冲
    区写满时才刷新出去,除非强制新

与文件类型有关:

  • 写入显示器对应行缓冲
  • 写入普通文件对应全缓冲

printf 和fwrite 输出了两次write输出了一次。

c库函数般自带缓冲区,当重定项到普通文件中时,行缓冲转换为全缓冲,此时缓冲区中的文件不会被刷新,直到调用fork之后,父子进程代码共享,因为缓冲区中的数据未被刷新,因此子进程写时拷贝私有一份,直到进程缓冲区刷新。产生两份数据。
write未发生变化,说明write没有缓冲区

printf fwrite C库函数自带缓冲区,write 系统调用接口路没有。


实现简单的模拟shell程序
添加输入 输出 追加 重定项

 1 #include <stdio.h>                                                        
    2 #include <unistd.h>                                                       
    3 #include <sys/wait.h>                                                     
    4 #include <stdlib.h>                                                       
    5 #include <string.h>                                                       
    6 #include <sys/stat.h>                                                     
    7 #include <fcntl.h>                                                        
    8                                                                           
    9                                                                           
   10 int main()                                                                
   11 {                                                                         
   12                                                                           
   13   char cmd[1024];                                                         
   14   char* myargv[16];                                                       
   15   int  fd=-1;                                                             
   16   while(1)                                                                
   17 {                                                                         
   18                                                                           
   19    printf("[wens@localhost myshell]# ");                                  
   20                                                                           
   21    fgets(cmd,sizeof(cmd),stdin);              
     22                                                                           
   23    int i=0;                                                               
   24                                                                           
   25    cmd[strlen(cmd)-1]='\0';                                               
   26                                                                           
   27    myargv[i++]=strtok(cmd," ");//将字符串分割解析                         
   28                                                                           
   29    char *ret=NULL;                                                        
   30                                                                           
W> 31    while(ret=strtok(NULL," "))                                            
   32    {                                                                      
   33       myargv[i++]=ret;                                                    
   34    }                                                                      
   35                                                                           
   36    myargv[i]=NULL;                                                        
   37                       
    38 //  for( j=0;j<i;j++)                                                     
   39 //     printf("%s\n",myargv[j]);                                          
   40                                                                           
   41                                                                           
   42                                                                           
   43                                                                           
   44                                                                           
   45                                                                           
   46    int j=0;                                                               
   47    pid_t id=fork();                                                       
   48    if(id==0)                                                              
   49   {                                                                       
   50  //   printf("child\n");                          
   51                                                                           
   52      for(j=0;j<i;j++)                                                     
   53      {                                                                    
   54      if(strcmp(myargv[j],">")==0)  //    输出重定项                                 
   55      {                                                                    
   56         close(1);                                                         
   57         fd=open(myargv[j+1],O_WRONLY|O_CREAT,0644);                       
   58  //srv  printf("%d\n",fd);                                                
   59        if(fd<0)                                                           
   60        {                                                                  
   61          perror("open");                                                  
   62          exit(1);                                                         
   63        }                                                                  
   64        myargv[j]=NULL;
   65        i=j;
   66       break;
   67      }
   68      else if(strcmp(myargv[j],"<")==0)   //输入重定项
   69      {                                                                    
   70        close(0);                                                          
   71         fd=open(myargv[j+1],O_RDONLY,0644);                               
   72        if(fd<0)                                                           
   73        {                                                                  
   74          perror("open");                                                  
   75          exit(1);                                                         
   76        }                                                                  
   77                                                                           
   78        myargv[j]=NULL;                                                    
   79        i=j;                                                               
   80       break;                                                              
   81      }   else if(strcmp(myargv[j],">>")==0)             //追加重定项                  
   82      {
   83        close(1);
   84        fd=open(myargv[j+1],O_WRONLY|O_CREAT|O_APPEND,0644);
   85        if(fd<0)
   86        {
   87          perror("open");                                                  
   88          exit(1);                                                         
   89        }                                                                  
   90                                                                           
   91        myargv[j]=NULL;
   92        i=j;
   93       break;
   94      }
   95 
   96      }                                                                    
   97        execvp(myargv[0],myargv);                                          
   98          //进行程序替换                                                   
   99                                                                           
  100        exit(1);                                                           
  101                                                                           
  102     }else{                                                                
  103   //    printf("parent\n");                                               
  104      waitpid(id,NULL,0);  //等待子进程                                    
  105         }                                                                 
  106 }                                                                         
  107                                                                           
  108                                                                           
  109 return 0;
  110 
  111 }

输出重定项

[wens@localhost newshell]$ ./newshell
[wens@localhost myshell]# ls
Makefile  newshell  newshell.c
[wens@localhost myshell]# ls > pp
[wens@localhost myshell]# cat pp
Makefile
newshell
newshell.c
pp
[wens@localhost myshell]# 

输入重定项

[wens@localhost myshell]# wc < pp
  9  14 116
[wens@localhost myshell]# cat < pp
Makefile
newshell
newshell.c
pp
newshell:newshell.c
	gcc -o newshell newshell.c
.PHONY:clean
clean:
	rm -f newshell
[wens@localhost myshell]# 
 

追加重定项

[wens@localhost myshell]# cat Makefile >> pp
[wens@localhost myshell]# cat pp
Makefile
newshell
newshell.c
pp
newshell:newshell.c
	gcc -o newshell newshell.c
.PHONY:clean
clean:
	rm -f newshell
[wens@localhost myshell]# 

猜你喜欢

转载自blog.csdn.net/M_jianjianjiao/article/details/83241954