当前位置: 首页 > backend >正文

Linux:缓冲区

一:重定向 

./stream > log.txt 在这行代码中,我们将运行stream得到的结果重定向到 log.txt 这个文件中,而实际上这行代码的完整写法为./stream 1 > log.txt,即将运行stream得到的结果从标准输出(stdout文件描述符为1)重定向到 log.txt 这个文件中

 stream.cc代码:

  1 #include<iostream>2 #include<cstdio>3 4 int main()5 {6     //向标准输出打印,stdout 17     std::cout << "hello cout" << std::endl;8     printf("hello printf\n");9 10     //向标准错误打印,stderr 211     std::cerr << "hello cerr" << std::endl;12     fprintf(stderr,"hello stderr\n");13 14     return 0;15 }

如上面代码所示:我们分别在标准输出(cout)打印hello cout语句并使用printf函数打印hello printf语句和在标准错误(cerr)打印hello cerr语句并使用fprintf函数向标准输出stderr打印hello stderr语句,而两者都是通过显示器打印,结果如下所示:

但如下面两张图所示,我们发现将运行stream得到的结果重定向到 log.txt 这个文件中时只打印了hello cerr和hello stderr这两条语句,而打印log.txt文件中的内容时只打印了hello cout和hello printf这两条语句。这是为什么呢?这是因为执行./stream > log.txt语句时是将stream执行的结果从标准输出(stdout)重定向到log.txt文件中,(即在log.txt文件中写入hello cout和hello printf语句)而另外两条语句是在标准错误文件中,因此执行./stream > log.txt语句时会将还存在显示器上的hello erro和stderr语句打印出来,即执行./stream > log.txt语句只做了标准输出的重定向而没有做标准错误的重定向

 

1-1 :那如果我们想做标准错误的重定向呢?

向指定文件进行标准错误的重定向:

./stream 1>log.normal 2>log.error

如上图所示:在显示器上输入上面语句,即将执行stream文件的结果并将标准输出(1)重定向到log.normal文件中;将标准错误(2)重定向到 log.error文件中 。这样就可以将标准错误重定向到log.error这个文件中了

把标准输出和标准错误重定向到同一个文件:

方法1:

./stream 1>log.normal 2>>log.normal

如上图所示:我们将执行stream文件的结果并将标准输出(1)重定向到log.normal文件中;并且将标准错误(2)追加到 log.normal文件中。这样就可以将标准输出和标准错误重定向到同一个文件中了 

方法2:

./stream 1>log.txt 2>&1

 如上图所示:我们将执行stream文件的结果并将标准输出(1)重定向到log.txt文件中;并且将标准错误重定向到与标准输出相同目标的文件中(即log.txt)

二:缓冲区

stream.cc代码:

  1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<unistd.h>5 #include <sys/types.h>6 #include <sys/stat.h>7 #include <fcntl.h>8 9 int main()10 {11     close(1);12     int fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND,0666);13     //C语言标准库14     printf("fd:%d\n",fd);15     printf("hello world\n");16     printf("hello world\n");17     printf("hello world\n");18 19     //系统调用20     const char* msg = "hello write\n";21     write(fd,msg,strlen(msg));22 23     //close(fd);24     return 0;25 }

如上面代码所示:我们先关闭标准输出文件,然后以追加方式创建一个权限位为0666的文件log.txt,由所学可知,fd的值为1,因此将标准输出重定向到log.txt文件中,接着打印log.txt的文件描述符,打印三行hello world语句,接着调用write函数向log.txt文件中写入长度为msg的字符串msg,先不关闭文件log.txt, 因此打印log.txt所有内容都显示

在这里我们将关闭文件log.txt, 这时我们将拿不到fd的值,因此C语言标准库想通过fd系统调用write函数时将会失败,因此C语言缓冲区中的内容将不能刷新到文件内核缓冲区,只有系统调用函数write中的内容在文件内核缓冲区内,所以最后return的时候只能打印hello write这条语句

缓冲区刷新条件:

  1. 强制刷新(调用fflush)
  2. 刷新条件满足(行刷新)
  3. 进程退出(return语句)

缓冲区刷新流程:如果是C/C++等标准库函数的刷新,例如printf函数的刷新,会在C语言标准库中建一个语言层的缓冲区,将需要刷新的语句放在这个缓冲区中,当条件满足时C标准库就会通过fd和系统调用write将语言层的缓冲区的内容拷贝给操作系统,然后再拷贝到文件内的缓冲区。即条件满足就会将语言标准库中的内容刷新到文件内核缓冲区,当最后将文件内核缓冲区内的内容刷新到硬件中(如显示器);而系统调用函数如write函数的内容本身就刷新到文件内核缓冲区

例子1:stream.cc代码:

  1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<unistd.h>5 6 int main()7 {8     //库函数9     printf("hello world\n");10     fprintf(stdout,"hello fprintf\n");11     const char* s = "hello fwrite\n";12     fwrite(s,strlen(s),1,stdout);13 14     //系统调用15     const char* ss = "hello write\n";16     write(1,ss,strlen(ss));17 18 19     return 0;20 }

如上面代码所示:我们使用printf函数打印hello world语句,fprintf函数向标准输出打印hello fprintf

fwrite函数向标准输出写入长度为s的字符串s,最后调用系统函数write向标准输出打印hello write语句,结果如下图所示:

将标准输出中的内容重定向到log.txt文件中,并且打印log.txt文件中的内容如下如所示:

例子2:stream.cc代码: 

  1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<unistd.h>5 6 int main()7 {8     //库函数9     printf("hello world\n");10     fprintf(stdout,"hello fprintf\n");11     const char* s = "hello fwrite\n";12     fwrite(s,strlen(s),1,stdout);13 14     //系统调用15     const char* ss = "hello write\n";16     write(1,ss,strlen(ss));17 18     fork();19     return 0;20 }

 如上面代码所示:我们在调用write函数后创建一个子进程,执行结果和上面代码一样,如下图所示:

 但是我们发现打印log.txt文件中的内容时和上一个例子中的运行结果不一样,除了hello write语句之外的另外三条语句都打印了两次,这是因为hello world、hello fprintf和hello fwrite这三条语句都是存储在C语言标准库的缓冲区中,调用fork进程时会创建子进程因此子进程会从C语言标准库的缓冲区中拿到这三条语句并向C语言标准库的缓冲区中写入(即父进程和子进程都会执行者三条语句),而hello write这条语句没有输出两次的原因是hello write这条语句存储在文件内核缓冲区中执行该语句之后就会在显示器上显示这条语句,最后执行return语句时就会将C语言标准库的缓冲区中的内容向文件内核缓冲区中拷贝并刷新,最后在显示器打印

三:自定义glib.c

mystdio.h代码:

  1 #pragma once2 #include<stdio.h>3 4 #define MAX 10245 6 #define NONE_FLUSH (1 << 0)7 #define LINE_FLUSH (1 << 1)8 #define FULL_FLUSH (1 << 2)9 10 typedef struct IO_FILE11 {12     int fileno;13     int flag;14     char outbuffer[MAX];15     int bufferlen;16     int flush_method;17 }MyFile;18 19 MyFile* MyFopen(const char* path,const char* mode);20 void MyFclose(MyFile*);21 int MyFwrite(MyFile*,void* str,int len);22 void MyFFlush(MyFile*);23 

mystdio.c代码:

  1 #include"mystdio.h"2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<string.h>5 #include<fcntl.h>6 #include<stdlib.h>7 #include<unistd.h>8 9 static MyFile* BuyFile(int fd,int flag)10 {11     MyFile* f = (MyFile*)malloc(sizeof(MyFile));12     if(f == NULL)13         return NULL;14 15     f->bufferlen = 0;16     f->fileno = fd;17     f->flag = flag;18     f->flush_method = LINE_FLUSH;19     memset(f->outbuffer,0,sizeof(f->outbuffer));20     return f;21 }22 23 MyFile* MyFopen(const char* path,const char* mode)24 {25     int fd = -1;26     int flag = 0;27 28     if(strcmp(mode,"w") == 0)29     {30         flag = O_CREAT | O_WRONLY | O_TRUNC;31         fd = open(path,flag,0666);32     }33     else if(strcmp(mode,"a") == 0)34     {35         flag = O_CREAT | O_WRONLY | O_APPEND;36         fd = open(path,flag,0666);37     }38     else if(strcmp(mode,"r") == 0)39     {40         flag = O_RDONLY;41         fd = open(path,flag);42     }43     else44     {45     }46 47     if(fd < 0)48         return NULL;49 50     //创建文件51     return BuyFile(fd,flag);52 }53 54 void MyFclose(MyFile* file)55 {56     if(file->fileno < 0)57         return;58     MyFFlush(file);59     close(file->fileno);60     free(file);61 }62 63 int MyFwrite(MyFile* file,void* str,int len)64 {65     //拷贝66     memcpy(file->outbuffer + file->bufferlen,str,len);67     file->bufferlen += len;68 69     //刷新70     if((file->flush_method & LINE_FLUSH) && file->outbuffer[file->bufferlen - 1] == '\n')71     {72         MyFFlush(file);73     }74     return 0;75 }76 77 void MyFFlush(MyFile* file)78 {79     int n = write(file->fileno,file->outbuffer,file->bufferlen);80     file->bufferlen = 0;81 }

http://www.xdnf.cn/news/8000.html

相关文章:

  • BigFoot (DBM) Deadly Boss Mods
  • DL00988-稀疏增强数据transformer船舶AIS轨迹预测含完整数据集
  • 腾讯文档怎么设置多列筛选条件
  • 固定翼无人机抛投技术分析!
  • 从零基础到最佳实践:Vue.js 系列(5/10):《状态管理》
  • 11-帮助中心
  • cmd如何从C盘默认路径切换到D盘某指定目录
  • 前端之vue3创建基本工程,基本登录、注册等功能的完整过程
  • 【IC验证】systemverilog_包
  • 自由开发者计划 001:创建一个用于查看 Jupyter Notebook 的谷歌浏览器插件 Jupyter Peek
  • 常见的LLM
  • 从零基础到最佳实践:Vue.js 系列(2/10):《模板语法与数据绑定》
  • 对抗学习(AL),生成对抗网络(GAN),强化学习,RLHF
  • 【差异分析】t-test
  • React中 lazy与 Suspense懒加载的组件
  • 26、AI 预测性维护 (燃气轮机轴承) - /安全与维护组件/ai-predictive-maintenance-turbine
  • 鸿蒙电脑系统和统信UOS都是自主可控的系统吗
  • 从零开始:Python语言基础之条件语句(if-elif-else)
  • Java虚拟机栈
  • 社会工程与信息收集
  • 左手腾讯CodeBuddy 、华为通义灵码,右手微软Copilot,旁边还有个Cursor,程序员幸福指数越来越高了
  • Human Dil-HDL,使用方法,红色荧光标记人源高密度脂蛋白
  • 循环队列分析及应用
  • 在 Qt 中实现动态切换主题(明亮和暗黑)
  • Gartner研究报告《Generative AI 赋能Digital Commerce的三种路径》学习心得
  • 笑林广记读书笔记三
  • 下一代电子电气架构(EEA)的关键技术
  • 具有思考模式模型部署:Qwen3、DeepSeek-R1-Distill、Phi-4、QWQ系列
  • 模型量化与保存
  • Python实例题:Python实现简单画板