Linux —— 基础I/O(二)

目录

一,FILE

二,缓冲区

三,重定向

系统调用dup2


一,FILE

  • FILE结构体内部包括
    • 变量**_fileno**,即对应的文件描述符下标fd
    • 应用层C语言提供的缓冲区数据
  • 其IO相关函数与系统调用接口对应,封装了系统调用接口,本质上是通过fd访问;
  • 向普通文件写入是全缓冲,向屏幕文件写入是行缓冲;
cpp 复制代码
//语言层次上
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;    
} 
bash 复制代码
[wz@192 Desktop]$ ./target 
stdin fd=0
stdout fd=1
stderr fd=2
log.txt fd=3
cpp 复制代码
//路径/usr/include/stdio.h
 typedef struct _IO_FILE FILE;  
cpp 复制代码
//路径/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
};  

二,缓冲区

cpp 复制代码
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;
}
bash 复制代码
//向屏幕刷新策略为行缓冲
[wz@192 Desktop]$ ./target 
hello printf
hello fprintf
hello fputs
hello write
bash 复制代码
//去掉\n,除了系统调用只打印一个,其他都打印两个;
[wz@192 Desktop]$ ./target 
hello writehello printfhello fprintfhello fputshello printfhello fprintfhello fputs
bash 复制代码
//输出重定向后,刷新策略改为全缓冲
//除了系统调用只打印一个,其他都打印两个;
[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会通过内核级的缓冲区;

三,重定向

cpp 复制代码
//关闭默认打开的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;    
}   
bash 复制代码
//此时不仅没有打印到屏幕,也没有写入到log.txt
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
[wz@192 Desktop]$ 
cpp 复制代码
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;    
}   
bash 复制代码
//刷新到了log.txt文件
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
log.txt fd=1

系统调用dup2

cpp 复制代码
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;    
}  
cpp 复制代码
//重定向后,向log.txt文件写入了
[wz@192 Desktop]$ ./target 
[wz@192 Desktop]$ cat log.txt 
write dup2
cpp 复制代码
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;    
}  
bash 复制代码
//重定向后,从文件读取数据
[wz@192 Desktop]$ ./target 
wirte dup2
相关推荐
RussellFans4 分钟前
Linux 环境配置
linux·运维·服务器
高冷的肌肉码喽1 小时前
Linux-进程间的通信
linux·运维·服务器
乖乖是干饭王1 小时前
Linux系统编程中的_GNU_SOURCE宏
linux·运维·c语言·学习·gnu
jekc8681 小时前
禅道18.2集成LDAP
linux·运维·服务器
weixin_434936281 小时前
k8S 命令
linux·容器·kubernetes
weixin_307779131 小时前
Linux下GCC和C++实现统计Clickhouse数据仓库指定表中各字段的空值、空字符串或零值比例
linux·运维·c++·数据仓库·clickhouse
Tender_光3 小时前
iptables实验
运维·服务器
szxinmai主板定制专家3 小时前
【飞腾AI加固服务器】全国产化飞腾+昇腾310+PCIe Switch的AI大模型服务器解决方案
运维·服务器·arm开发·人工智能·fpga开发
点击查询3 小时前
怎么把自己电脑设置成服务器?
运维·服务器
阿里云大数据AI技术4 小时前
ES Serverless 8.17王牌发布:向量检索「火力全开」,智能扩缩「秒级响应」!
大数据·运维·serverless