栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Linux篇11基础IO

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux篇11基础IO

1.回顾c语言的文件操作
#include 

int main()
{

 // FILE* fp = fopen("log.txt", "r");
  FILE* fp = fopen("log.txt", "a");//a追加 log.txt不存在就会在当前路径下创建一个
  //所谓当前路径,不是指当前可执行程序所处的路径,而是进程运行时所处的路径
  if(fp == NULL)//打开失败
  {
    perror("fopen");
    return 1;
  }
//  char buffer[100];
//  int ct = 5;
//  while(ct--)
//  {
//   // fgets(buffer, sizeof(buffer), fp);
//   // fgets(buffer, sizeof(buffer), stdin);//stdin--从键盘输入
//    printf(buffer);
//
//  }
  int count = 5;
  while(count--)
  {
    fputs("hello Linuxn", fp);
  }
  fclose(fp);
  return 0;
}

  • stdin & stdout & stderr

    C默认会打开三个输入输出流,分别是stdin, stdout, stderr。这三个流的类型都是FILE*, fopen返回值类型,文件指针

    stdin:键盘 标准输入

    stdout:显示器 标准输出

    stderr:显示器 标准错误

2.系统文件I/O

在c语言里面,有fopen,fclose,fread,fwrite这些函数。而open,close,read,write都属于系统提供的接口,称之为系统调用接口。实际上,Linux环境使用fopen底层调用的还是open。那么c语言为什么还要弄出来一个fopen呢。这是为了保证c语言的跨平台性,比如在win下面,也有与fopen对应的系统调用接口。这样就可以实现c语言在Linux下掉Linux对应的系统调用接口,在win下调用win对应的系统调用接口。

3.文件描述符fd

文件描述符是一个整数,实际上是一个数组的下标

  • 0 & 1 & 2

    Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2。0,1,2对应的物理设备一般是:键盘,显示器,显示器。虽然1 2 都对应显示器,但是他们是不同的。标准错误是不能被重定向的,只会打印到显示器上。

  • fopen到底在干什么?
    1. 给用户申请struct file结构体,并返回地址file*
    2. 在底层通过open打开文件,并返回fd,把fd填充进struct file结构体里面的fileno。
4.缓冲区

凡是显示到显示器上面的内容,都是字符,凡是键盘读取的内容都是字符,所以键盘和显示器一般被称为“字符设备”

缓冲:

  • 无缓冲

  • 行缓冲(常见的对显示器刷新数据时)

    一行输入满了再一起刷新到显示器上面。所以我们在printf打印的时候,如果不加n是不会立刻打印到显示器上面的,如果想立刻打印到显示器上面可以使用fflush

    进程在退出的时候会将用户区的缓冲区内容刷新到os缓冲区

  • 全缓冲(对文件写入的时候)

    整个缓冲区满了再刷新到磁盘

以上所说的缓冲区是c语言自带的,其实操作系统也有缓冲区,上面说的刷新到显示器,刷新到磁盘,其实不是一步完成的,而是c语言的缓冲区刷新到os的缓冲区,再由os的缓冲区刷新到显示器/硬盘。这里我们不关心os的缓冲区是如何刷新的

下面我们看一下这段代码

#include 
#include 
#include 
#include 
#include 
#include 
int main()
{
  //c语言函数
  printf("hello printfn");
  fprintf(stdout, "hello fprintfn");
  //system
  const char* msg = "hello writen";
  write(1, msg, strlen(msg));
  fork();
  return 0;
}

我们对上面代码做以下4种测试

  1. 注释fork()不创建子进程,不重定向

  2. 注释fork()不创建子进程,重定向

  3. 创建子进程,不重定向

  4. 创建子进程,重定向

对比结果我们发现:

  • 不重定向的打印顺序正常,而重定向之后先打印了hello write。
  • 创建子进程并重定向,hello printf 和hello fprint打印两次

原因:重定向之后,由于hello write是系统调用,没有缓冲区,直接打印出来,而hello printf和 hello fprint重定向之后,由行缓冲变成全缓冲,不会立刻打印出来,要等到进程结束才刷新缓冲区。当创建子进程不重定向,子进程相当于什么也没做。而创建子进程并且重定向时,父进程的hello printf和hello fprintf还在缓冲区,子进程由于写时拷贝,也有一份hello printf和hello fprintf。当父子进程结束,刷新缓冲区,父子进程的hello printf和hello fprintf都写入到log.txt。

5.dup2
#include 
int dup2(int oldfd, int newfd);
dup2() makes newfd be the copy of oldfd, closing newfd first if  necessary, but note the following:

       *  If  oldfd  is  not a valid file descriptor, then the call fails, and
          newfd is not closed.

       *  If oldfd is a valid file descriptor, and newfd has the same value as
          oldfd, then dup2() does nothing, and returns newfd.

 int main()
 {
     umask(0);
     int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);
     dup2(fd, 1);  
     printf("hahan");//原本打印到显示器就是写入到log.txt
     close(fd);
     return 0;
 }


                
                
                
        
        

  
    
      
        
      
      
        
          
          
        
        
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1004461.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号