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
相关推荐
历程里程碑3 分钟前
Linux 5 目录权限与粘滞位详解
linux·运维·服务器·数据结构·python·算法·tornado
zuozewei14 分钟前
零基础 | AI应用记忆管理:从短期到长期的完整实践指南
运维·服务器·人工智能
馨谙35 分钟前
shell编程实际应用----磁盘空间监控与告警
linux·运维·服务器
跃渊Yuey39 分钟前
【Linux】线程概念
linux
njsgcs40 分钟前
MiniCPM4-0.5B-QAT-Int4-GPTQ-format 小显存llm
linux·人工智能
UP_Continue1 小时前
Linux--命令行参数和环境变量
linux·运维·服务器
重生之绝世牛码1 小时前
Linux软件安装 —— PostgreSQL高可用集群安装(postgreSQL + repmgr主从复制 + keepalived故障转移)
大数据·linux·运维·数据库·postgresql·软件安装·postgresql高可用
Calebbbbb1 小时前
Ubuntu 24.04 + Android 15 (AOSP) 环境搭建与源码同步完整指南
android·linux·ubuntu
STCNXPARM1 小时前
Linux PCI/PCIe子系统深度剖析
linux·运维·服务器·pci/pcie
郝学胜-神的一滴2 小时前
深入理解Linux套接字(Socket)编程:从原理到实践
linux·服务器·开发语言·网络·c++·程序人生·算法