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
相关推荐
程序员南飞40 分钟前
ps aux | grep smart_webrtc这条指令代表什么意思
java·linux·ubuntu·webrtc
StrokeAce40 分钟前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
热爱嵌入式的小许5 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风8 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学8 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO9 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu79 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我9 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、9 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程9 小时前
Linux中环境变量
linux