基础IO(输出重定向,输入重定向 ,追加重定向,dup2)【Linux】

fopen

在这里插入图片描述
第一个参数是你要打开的文件的文件名,第二个参数是打开这个文件的形式
在这里插入图片描述
-w : 打开文件前,都会对文件进行清空处理,重新开始写
-a : 在文件结尾追加写

当前路径

例如:
在这里插入图片描述

第一个参数如果不带路径 , 默认会在当前路径下新建一个文件,当前的路径就是进程的当前路径cwd
在这里插入图片描述
如果需要更改当前进程的cwd,把文件新建到其他目录
可以使用chdir
在这里插入图片描述

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 int main()
  4 {
  5   chdir("/home/cxq");
  6   printf( " pid:%d\n", getpid() );
  7   FILE*  fp =  fopen( "logggggggggggggggg.txt" , "w" );                                                                             
  8   if(fp==NULL)                                                                       
  9   {                                                                                  
 10     perror("fopen");                                                                 
 11     return 1 ;                                                                       
 12   }                                                                                  
 13   fclose(fp);                                                                        
 14   sleep(10000);                                                                      
 15   return 0;                                                                          
 16 }  

在这里插入图片描述
如果第一个参数带了绝对路径,就按绝对路径来

fprintf

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 int main()
  5 {
  6   printf( " pid:%d\n", getpid() );
  7   FILE*  fp =  fopen( "log.txt" , "a" );
  8   if(fp==NULL)
  9   {
 10     perror("fopen");
 11     return 1 ;
 12   }
 13  const char * message ="abcd\n";
 15 fprintf(fp, "%s : %d\n", message , 1234);                                                                                           
 18   fclose(fp);
 20   return 0;
 21 }

stdin && stdout && stderr

在这里插入图片描述

FILE * : C库自己封装的结构体,这里面一定封装了文件描述符

C程序默认在启动的时候,会打开三个标准输入输出流(文件):
stdin:键盘文件
stdout:显示器文件
stderr:显示器文件

向显示器里打印

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 int main()
  5 {
  6   printf( " pid:%d\n", getpid() );
  7   FILE*  fp =  fopen( "log.txt" , "a" );
  8   if(fp==NULL)
  9   {
 10     perror("fopen");
 11     return 1 ;
 12   }
 13  const char * message ="abcd\n";
 16 fprintf(stdout, "%s : %d\n", message , 1234);                                                                                       
 19   fclose(fp);
 21   return 0;
 22 }

几乎所有的库只要是访问硬件设备,必定要封装系统调用
printf、fprintf、fscanf、fwrite、fread、fgets、gets 等这些都是库函数,
库函数底层封装了系统调用接口

umask函数将权限掩码设置为0

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<sys/types.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 int main (  )
  8 {
  9 umask(0);                                                                                                            
 10  int fd = open("log.txt" , O_WRONLY | O_CREAT , 0666 );
 11  //open失败
 12  if( fd< 0 )
 13  {
 14    printf( "open file error\n" );
 15    return 1 ;
 16  }
 17   return 0 ;
 18 
 19 }

O_WRONLY 文件以写的方式打开
O_CREAT 如果文件不存在,就创建
O_TRUNC 打开文件之前先清空文件
O_APPEND 追加写
O_RDONLY是只读

open

open
在这里插入图片描述
open
在这里插入图片描述

在这里插入图片描述

结论:

FILE*fp = fopen("log.txt", "w");//fopen的w选项底层调用的就是O_WRONLY|O_CREAT|O_TRUNC,fopen底层一定对open进行了封装
int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
FILE *fp = fopen("loq.txt". "a");//fopen的a选项底层调用的就是O_WRONLY|O_CREAT|O_APPEND,fopen底层一定对open进行了封装
int fd = open("log.txt",O_WRONLY|O_CREAT|O_APPEND,0666);

文件描述符对应的分配规则:
*从struct file fd_array[]这个数组的0下标开始,线性遍历寻找,最小且未使用的数组下标位置,此时这个下标就是新文件的文件描述符

当你打开一个文件时,会在数组中分配一个没有被占用的下标,把该struct file的地址填充到对应的数组下表中
在这里插入图片描述
open函数的返回值int , 返回的就是struct file *fd_array[]这个数组的下标

数组下标 0 1 2 ,分别对应:
stdin (0)
stdout(1)
stderr(2)

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<sys/types.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 int main (  )
  8 {
 10   const char * mes ="hello Linux\n";
 11   //向stdout中写
 12   write(1, mes ,  strlen(mes) );
 14   //向stderr中写                                       
 15   write(2, mes ,  strlen(mes) );
 32   return 0 ; 
 34 }
  1 #include<stdio.h>  
  2 #include<unistd.h>  
  3 #include<string.h>  
  4 #include<sys/types.h>  
  5 #include<sys/stat.h>  
  6 #include<fcntl.h>  
  7 int main (  )  
  8 {  
  9  char buffer [1024];  
 10  // 0:stdin  
 11    ssize_t s =   read(0, buffer , sizeof(buffer ) );  
 12   if(s< 0)  
 13   {  
 14     return 1 ;  
 15   }
 16   buffer[s]='\0';  //操作系统只认为读取的是一个一个的字符   ,也就是说操作系统不知道读取的是否是字符串,而C语言将读入的信息当成字符串 ,所以加\0                                                                              
 17 printf( "echo  %s\n", buffer );
 32   return 0 ; 
 34 }

程序默认在启动的时候,操作系统会打开stdin(键盘文件) 、 stdout(显示器文件) 、stderr(显示器文件),
进程默认会打开键盘,显示器,显示器

在这里插入图片描述
C库自己封装的结构体,这里面一定封装了文件描述符

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<sys/types.h>
  5 #include<sys/stat.h>
  6 #include<fcntl.h>
  7 int main (  )
  8 {
  9 
 10  printf("stdin->fd: %d\n", stdin->_fileno);
 11  printf("stdout->fd: %d\n", stdout->_fileno);
 12  printf("stderr->fd: %d\n", stderr->_fileno); 
 32   return 0 ; 
 34 }

在这里插入图片描述

重定向

输出重定向:
将我们本来输出到一个文件的数据重定向输出到另一个文件中
在这里插入图片描述

重定向原理:对进程的指定文件描述符表,将表中的地址进行拷贝

将数组对应下标的内容作修改
在这里插入图片描述

close(1) 执行后 ,将数组下标为1的进行了修改,本来是数组下标为1的指针指向显示器文件,后修改为指向log.txt

dup2

在这里插入图片描述

dup2会将struct file *fd_array[oldfd]的内容拷贝到struct file *fd_array[newfd]当中,如果有必要的话我们需要先使用关闭文件描述符为newfd的文件

将数组下标为3的指针log.txt file* ,拷贝并覆盖到数组下标为1的指针中,此时数组下标为1的指针就会指向log.txt了

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h>
  7 #define filename  "log.txt"
  8 
  9 
 10 
 11 int main()
 12 {
 13   //close(0);
 14    int fd = open(filename ,O_WRONLY|O_CREAT|O_TRUNC ,0666 );
 15    if(fd < 0)
 16    {
 17      perror("open");
 18      return 1 ;
 19    }
 20 
 21   // printf( " fd:%d\n " , fd );                                                                                                    
 22 //重定向
 23 dup2(fd, 1);
 24    const char * msg  = "hello Linux\n";
 25    int cnt =5 ;
 27    while(cnt!=0 )
 28    {
 29      write(1,msg , strlen(msg)  );
 31    cnt --;
 32    }
 33    close(fd);
 34   return 0 ;
 35 }

追加重定向

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h> 
  7 #define filename  "log.txt"                                                                                                         
  8 int main()
  9 {         
 10   //close(0);
 11    int fd = open(filename ,O_WRONLY|O_CREAT|O_APPEND ,0666 );
 12    if(fd < 0)                                                
 13    {                                                         
 14      perror("open");                                         
 15      return 1 ;     
 16    }                
 17                     
 18   // printf( " fd:%d\n " , fd );
 19 //重定向                        
 20 dup2(fd, 1);                    
 21 close(fd);                      
 22    const char * msg  = "hello Linux\n";
 23    int cnt =5 ;                        
 24                                        
 25    while(cnt!=0 )                      
 26    {             
 27      write(1,msg , strlen(msg)  );
 28                                   
 29    cnt --;                        
 30    }                              
 31    close(fd);
 32   return 0 ; 
 33 } 

输入重定向

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h> 
  7 #define filename  "log.txt"
  8 int main()
  9 {
 10   //close(0);
 11  //  int fd = open(filename ,O_WRONLY|O_CREAT|O_APPEND ,0666 );
 12   int fd = open(filename ,O_RDONLY ) ; // 是只读
 13    if(fd < 0)
 14    {
 15      perror("open");
 16      return 1 ;
 17    }
 21   char inbuffer[1024];
 22    ssize_t s =  read(0 , inbuffer , sizeof(inbuffer)-1);
 23    if(s>0)
 24    {
 25      inbuffer[s] ='\0';//操作系统只认为读取的是一个一个的字符   ,也就是说操作系统不知道读取的是否是字符串,而C语言将读入的信息当成>    字符串 ,所以加\0 
 26    printf("echo# %s\n", inbuffer);
 27    }
 47   return 0 ;
 48 }

本来从键盘文件中读取数据 ,加了dup2(fd , 0)之后 ,变成了从文件log.txt读取数据

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h> 
  7 #define filename  "log.txt"
  8 int main()
  9 {
 10   //close(0);
 11  //  int fd = open(filename ,O_WRONLY|O_CREAT|O_APPEND ,0666 );
 12   int fd = open(filename ,O_RDONLY ) ; // 是只读
 13    if(fd < 0)
 14    {
 15      perror("open");
 16      return 1 ;
 17    }
 18   //输入重定向
 19  dup2(fd , 0);
 20 
 21   char inbuffer[1024];
 22    ssize_t s =  read(0 , inbuffer , sizeof(inbuffer)-1);
 23    if(s>0)
 24    {
 25      inbuffer[s] ='\0';//操作系统只认为读取的是一个一个的字符   ,也就是说操作系统不知道读取的是否是字符串,而C语言将读入的信息当成>    字符串 ,所以加\0 
 26    printf("echo# %s\n", inbuffer);
 27    }
 47   return 0 ;
 48 }

进程历史打开的文件与进行的各种重定向关系都和未来进行的程序替换无关

也就是说程序替换,并不影响文件访问

  1 #include<stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include<unistd.h>
  6 #include<string.h> 
  7 #define filename  "log.txt"
  8 int main()
  9 {
 10 
 11  fprintf( stdout ,"hello normal message\n" );
 12  fprintf( stdout ,"hello normal message\n" );
 13  fprintf( stdout ,"hello normal message\n" );
 14  fprintf( stdout ,"hello normal message\n" );
 15  fprintf( stdout ,"hello normal message\n" );
 16 
 17  fprintf(stderr , "hello error message\n");
 18  fprintf(stderr , "hello error message\n");
 19  fprintf(stderr , "hello error message\n");
 20  fprintf(stderr , "hello error message\n");
 21  fprintf(stderr , "hello error message\n");
 71   return 0 ;
 72 }

在这里插入图片描述
在这里插入图片描述

原来stdout是指向显示器文件 , stderr是指向显示器文件,但是在执行这句命令./mytest > normal.log 后
stdout指向了normal.log ,stderr还是指向显示器文件

在这里插入图片描述

[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ ./mytest >normal.log 2>err.log
[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ ll
total 32
-rw-rw-r-- 1 cxq cxq  100 May 16 15:14 err.log
-rw-rw-r-- 1 cxq cxq   66 May 16 10:44 log.txt
-rw-rw-r-- 1 cxq cxq   80 May 14 16:22 Makefile
-rwxrwxr-x 1 cxq cxq 8448 May 16 14:44 mytest
-rw-rw-r-- 1 cxq cxq 1636 May 16 14:44 mytest.c
-rw-rw-r-- 1 cxq cxq  105 May 16 15:14 normal.log
[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ cat normal.log
hello normal message
hello normal message
hello normal message
hello normal message
hello normal message
[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ cat err.log
hello error message
hello error message
hello error message
hello error message
hello error message
[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ ./mytest 1>normal.log 2>err.log

./mytest >normal.log 2>err.log

./mytest 1>normal.log 2>err.log
上述两个写法是一样的

[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ ./mytest 1>all.log 2>&1
[cxq@iZ7xviiy0goapxtblgih6oZ lesson19]$ cat all.log
hello error message
hello error message
hello error message
hello error message
hello error message
hello normal message
hello normal message
hello normal message
hello normal message
hello normal message

2> &1:
在这里插入图片描述
如果你觉得这篇文章对你有帮助,不妨动动手指给点赞收藏加转发,给鄃鳕一个大大的关注你们的每一次支持都将转化为我前进的动力!!!

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鄃鳕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值