Linux —— 基础I/O(二)

文章详细解释了C语言中的FILE结构,涉及缓冲区工作原理,如行缓冲和全缓冲,以及重定向如何影响输出行为,特别是系统调用dup2的作用。讨论了标准输入、输出和错误的处理方式,以及内核和用户级缓冲的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,FILE

二,缓冲区

三,重定向

系统调用dup2 


一,FILE

  • FILE结构体内部包括
    • 变量_fileno,即对应的文件描述符下标fd
    • 应用层C语言提供的缓冲区数据
  • 其IO相关函数与系统调用接口对应,封装了系统调用接口,本质上是通过fd访问;
  • 向普通文件写入是全缓冲,向屏幕文件写入是行缓冲;

//语言层次上
int main()    
{    
    printf("stdin fd=%d\n",stdin->_fileno);    
    printf("stdout fd=%d\n",stdout->_fileno);    
    printf("stderr fd=%d\n",stderr->_fileno);                                        
    FILE* fp = fopen("log.txt", "r");    
    printf("log.txt fd=%d\n",fp->_fileno);    
    pclose(fp);    
    return 0;    
} 
[wz@192 Desktop]$ ./target 
stdin fd=0
stdout fd=1
stderr fd=2
log.txt fd=3

//路径/usr/include/stdio.h
 typedef struct _IO_FILE FILE;  
//路径/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
};  

二,缓冲区

int main()
{
    //C语言
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    fputs("hello fputs\n", stdout);

    //system call
    const char* msg = "hello write\n";
    write(1, msg, strlen(msg));
    
    fork();
    return 0;
}
//向屏幕刷新策略为行缓冲
[wz@192 Desktop]$ ./target 
hello printf
hello fprintf
hello fputs
hello write
//去掉\n,除了系统调用只打印一个,其他都打印两个;
[wz@192 Desktop]$ ./target 
hello writehello printfhello fprintfhello fputshello printfhello fprintfhello fputs
//输出重定向后,刷新策略改为全缓冲
//除了系统调用只打印一个,其他都打印两个;
[wz@192 Desktop]$ ./target > log.txt
[wz@192 Desktop]$ cat log.txt 
hello write
hello printf
hello fprintf
hello fputs
hello printf
hello fprintf
hello fputs
  • 库函数均刷新了两次,系统调用只刷新了一次;
  • 库函数会自带缓冲区,重定向到普通文件,刷新策略会从行缓冲改为全缓冲;没有指定刷新,就会在进程结束时统一刷新;fork时,父子数据会发生写实拷贝;
  • 系统调用没有所谓的用户级缓冲区,但OS会通过内核级的缓冲区;

三,重定向

//关闭默认打开的1指向的文件,即stdout
//此时新创建的文件,fd将会是1
//本来printf应打印到显示器,此时应该写入到log.txt
int main()    
{    
    close(1);    
    int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);    
    printf("fd=%d\n",fd); 
    close(fd);                                                                                     
    return 0;    
}   
//此时不仅没有打印到屏幕,也没有写入到log.txt
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
[wz@192 Desktop]$ 

int main()    
{    
    close(1);    
    int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);    
    printf("fd=%d\n",fd); 
    fflush(stdout);
    close(fd);                                                                                     
    return 0;    
}   
//刷新到了log.txt文件
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
log.txt fd=1

系统调用dup2 

int main()    
{    
    int fd = open("log.txt", O_WRONLY|O_CREAT, 0644);    
    if(fd<0){    
      perror("open");    
    }    
    dup2(fd,1);    
    const char* msg = "write dup2\n";                                                                                   
    write(1, msg, strlen(msg));
    close(fd);
    return 0;    
}  
//重定向后,向log.txt文件写入了
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
write dup2
int main()    
{    
    int fd = open("log.txt", O_RDONLY);                                              
    if(fd<0){    
      perror("open");    
    }    
    dup2(fd,0);    
    char buf[1024];    
    ssize_t r_size = read(0, buf, sizeof(buf)-1);    
    if(r_size>0){
        buf[s]=0;
        printf("%s\n",buf);   
    } 
    close(fd);    
    return 0;    
}  
//重定向后,从文件读取数据
[wz@192 Desktop]$ ./target 
wirte dup2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值