【Linux系统编程】 浅谈标准I/O缓冲区

简介:

标准I/O库提供缓冲的目的是尽可能地减少使用read和write调用的次数。它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的麻烦。不幸的是,标准I/O库最令人迷惑的也是它的缓冲。


标准I/O提供了三种类型的缓冲:

1、全缓冲:

在填满标准I/O缓冲区后才进行实际I/O操作。常规文件(如普通文本文件)通常是全缓冲的。


2、行缓冲:

当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。这允许我们一次输出一个字符,但只有在写了一行之后才进行实际I/O操作。标准输入和标准输出对应终端设备(如屏幕)时通常是行缓冲的。


3、不带缓冲:

用户程序每次调库函数做写操作都要通过系统调用写回内核(如系统调用函数)。标准错误输出通常是无缓冲的,这样用户程序产生的错误信息可以尽快输出到设备。


下面是各个缓冲区的验证。


全缓冲:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int main(int argc, char *argv[])  
  2. {  
  3.     FILE *fp = NULL;  
  4.     // 读写方式打开,文件不存在则创建  
  5.     fp = fopen("sunplusedu.txt""w+");  
  6.     if(NULL == fp)  
  7.     {  
  8.         printf("open error\n");  
  9.         return 1;  
  10.     }  
  11.     char *str = "sunplusedu\n";  
  12.     fwrite(str, 1, strlen(str), fp);    // 往文件写内容  
  13.     while(1);   // 程序阻塞在这里  
  14.   
  15.     return 0;  
  16. }  

运行程序发现,sunplusedu.txt并没有内容。因为常规文件通常是全缓冲的,只有缓冲区满了后,才会把内容写到文件中。接下来,我们改一下上面那个例子。


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     FILE *fp = NULL;  
  7.     // 读写方式打开,文件不存在则创建  
  8.     fp = fopen("sunplusedu.txt""w+");  
  9.     if(NULL == fp)  
  10.     {  
  11.         printf("open error\n");  
  12.         return 1;  
  13.     }  
  14.     char *str = "sunplusedu\n";  
  15.     int i = 0;  
  16.     while(i <= 512){ // 缓冲区大小不确定,i的大小只是一个调试值  
  17.         fwrite(str, 1, strlen(str), fp);    // 往文件写内容  
  18.         i++;  
  19.     }  
  20.     while(1);   // 程序阻塞在这里  
  21.   
  22.     return 0;  
  23. }  


上面的例子是循环给文件写内容,让缓冲区有填满的可能,结果发现,文件是有内容的。实际上要想成功给文件写进内容,除了缓冲区填满,还有别的方法。


1)人为关闭文件,就算缓冲区没有填满,内容也会写进文件

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     FILE *fp = NULL;  
  7.     // 读写方式打开,文件不存在则创建  
  8.     fp = fopen("sunplusedu.txt""w+");  
  9.     if(NULL == fp)  
  10.     {  
  11.         printf("open error\n");  
  12.         return 1;  
  13.     }  
  14.     char *str = "sunplusedu\n";  
  15.     fwrite(str, 1, strlen(str), fp);    // 往文件写内容  
  16.     fclose(fp);     // 人为关闭文件,就算缓冲区没有填满,内容也会写进文件  
  17.       
  18.     while(1);   // 程序阻塞在这里  
  19.   
  20.     return 0;  
  21. }  

2)程序正常结束,就算缓冲区没有填满,没有关闭文件,内容也会写进文件。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     FILE *fp = NULL;  
  7.     // 读写方式打开,文件不存在则创建  
  8.     fp = fopen("sunplusedu.txt""w+");  
  9.     if(NULL == fp)  
  10.     {  
  11.         printf("open error\n");  
  12.         return 1;  
  13.     }  
  14.     char *str = "sunplusedu\n";  
  15.     fwrite(str, 1, strlen(str), fp);    // 往文件写内容  
  16.       
  17.     return 0;  
  18.     // 程序正常结束,就算缓冲区没有填满,没有关闭文件,内容也会写进文件。  
  19. }  

行缓冲:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(int argc, char *argv[])  
  4. {  
  5.     printf("hello sunplusedu");  
  6.     while(1);  
  7.       
  8.     return 0;  
  9. }  

运行这个程序,会发现 hello sunplusedu 并没有打印到屏幕上。因为标准输入和标准输出对应终端设备时通常是行缓冲的,当在输入和输出中遇到换行符时,标准I/O库执行I/O操作。如下:


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(int argc, char *argv[])  
  4. {  
  5.     printf("hello sunplusedu\n");  
  6.     while(1);  
  7.       
  8.     return 0;  
  9. }  



除了遇到换行符,还有别的方法可以执行I/O操作。


1)缓冲区填满

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int main(int argc, char *argv[])  
  2. {  
  3.     while(1){   // 循环打印,总有缓冲区填满的可能  
  4.         printf("hello sunplusedu");  
  5.     }  
  6.     while(1);  
  7.       
  8.     return 0;  
  9. }  


2)人为刷新缓冲区

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(int argc, char *argv[])  
  4. {  
  5.     printf("hello sunplusedu");  
  6.     fflush(stdout); // 人为刷新  
  7.   
  8.     while(1);  
  9.       
  10.     return 0;  
  11. }  


3)程序正常结束

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2.   
  3. int main(int argc, char *argv[])  
  4. {  
  5.     printf("hello sunplusedu");  
  6.       
  7.     return 0;  
  8.     // 程序正常结束  
  9. }  


不带缓冲:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include <unistd.h>  
  2. #include <string.h>  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     char *str = "hello sunplusedu.com";   
  7.     // 有没有\n,缓冲区有没有填满,都没关系  
  8.     write(1, str, strlen(str)); // 往标准输出写内容  
  9.     while(1);  
  10.       
  11.     return 0;  
  12. }  
相关文章
|
1月前
|
Linux
Linux系统之whereis命令的基本使用
Linux系统之whereis命令的基本使用
74 24
Linux系统之whereis命令的基本使用
|
3月前
|
存储 缓存 监控
Linux缓存管理:如何安全地清理系统缓存
在Linux系统中,内存管理至关重要。本文详细介绍了如何安全地清理系统缓存,特别是通过使用`/proc/sys/vm/drop_caches`接口。内容包括清理缓存的原因、步骤、注意事项和最佳实践,帮助你在必要时优化系统性能。
300 78
|
2月前
|
缓存 安全 Linux
Linux系统查看操作系统版本信息、CPU信息、模块信息
在Linux系统中,常用命令可帮助用户查看操作系统版本、CPU信息和模块信息
157 23
|
3月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
135 13
|
3月前
|
Ubuntu Linux C++
Win10系统上直接使用linux子系统教程(仅需五步!超简单,快速上手)
本文介绍了如何在Windows 10上安装并使用Linux子系统。首先,通过应用商店安装Windows Terminal和Linux系统(如Ubuntu)。接着,在控制面板中启用“适用于Linux的Windows子系统”并重启电脑。最后,在Windows Terminal中选择安装的Linux系统即可开始使用。文中还提供了注意事项和进一步配置的链接。
97 0
|
4月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
417 8
|
4月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
1291 6
|
5天前
|
Linux
Linux od命令
本文详细介绍了Linux中的 `od`命令,包括其基本语法、常用选项和示例。通过这些内容,你可以灵活地使用 `od`命令查看文件内容,提高分析和调试效率。确保理解每一个选项和示例的实现细节,应用到实际工作中时能有效地处理各种文件查看需求。
41 19
|
16天前
|
缓存 Ubuntu Linux
Linux中yum、rpm、apt-get、wget的区别,yum、rpm、apt-get常用命令,CentOS、Ubuntu中安装wget
通过本文,我们详细了解了 `yum`、`rpm`、`apt-get`和 `wget`的区别、常用命令以及在CentOS和Ubuntu中安装 `wget`的方法。`yum`和 `apt-get`是高层次的包管理器,分别用于RPM系和Debian系发行版,能够自动解决依赖问题;而 `rpm`是低层次的包管理工具,适合处理单个包;`wget`则是一个功能强大的下载工具,适用于各种下载任务。在实际使用中,根据系统类型和任务需求选择合适的工具,可以大大提高工作效率和系统管理的便利性。
99 25
|
14天前
|
缓存 Linux
Linux查看内存命令
1. free free命令是最常用的查看内存使用情况的命令。它显示系统的总内存、已使用内存、空闲内存和交换内存的总量。 free -h • -h 选项:以易读的格式(如GB、MB)显示内存大小。 输出示例: total used free shared buff/cache available Mem: 15Gi 4.7Gi 4.1Gi 288Mi 6.6Gi 9.9Gi Swap: 2.0Gi 0B 2.0Gi • to
27 2