Linux第一个小程序——进度条 | 认识缓冲区
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
本章为 Linux 专栏第 8 课欢迎小伙伴们阅读学习~
------------------------------------------------------------------------------------
本章主要内容理解缓冲区的概念、利用缓冲区的性质实现进度条的小程序。
本章学习目标
1.巩固 make/makefile 的使用
2.练习Linux下多文件操作
3.了解缓冲区概念
gogogo
文章目录
1.认识缓冲区
缓冲区的概念
缓冲区是内存空间的一部分。也就是说在内存空间中预留了一定的存储空间这些存储空间用来缓冲输入或输出的数据这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备分为输入缓冲区和输出缓冲区。
如何证明缓冲区的存在
让我们通过一段简单的代码观察到缓冲区的存在。
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world");
//sleep函数——Linux中的一个休眠函数
sleep(3);
return 0;
}
按照正常的逻辑这段代码执行的结果应该是先打印 " hello world " 再休眠 3 秒。但是程序当执行后我们观察到的却是先停留了 3 秒又打印出 " hello world " 。
拼手速截的图小伙伴们可以手动尝试感受更深
在休眠的 3 秒期间数据 " hello world " 并没有刷新出来指的是没有打印在屏幕上3 秒之后才出现在屏幕上。那么在休眠的三秒期间数据 " hello world " 一定是被保存起来了那么保存到哪里了呢答案就是——缓冲区。
缓冲区有自己的刷新策略。一般系统默认程序结束后将缓冲区中的内容刷新出来也可以我们手动去刷新例如
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world");
//刷新缓冲区
fflush(stdout);
sleep(3);
return 0;
}
这次的执行结果是先打印了 " hello world " 再休眠 3 秒
缓冲区的作用
我们为什么要引入缓冲区呢
比如我们从磁盘里取信息我们先把读出的数据放在缓冲区计算机再直接从缓冲区中取数据等缓冲区的数据取完后再去磁盘中读取这样就可以减少磁盘的读写次数再加上计算机对缓冲区的操作大大快于对磁盘的操作故应用缓冲区可大大提高计算机的运行速度。
又比如我们使用打印机打印文档由于打印机的打印速度相对较慢我们先把文档输出到打印机相应的缓冲区打印机再自行逐步打印这时我们的CPU可以处理别的事情。现在您基本明白了吧缓冲区就是一块内存区它用在输入输出设备和CPU之间用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作避免低速的输入输出设备占用CPU解放出CPU使其能够高效率工作。
2.认识 '\n' 与 '\r'
'\n' 可以说是我们的老朋友了但是你真的了解他吗
我们电脑输入内容时是怎么确定要在哪个位置输入内容呢那就是看光标在哪个位置。
'\r' 的作用是——回车'/n' 的作用是——回车+换行
回车光标回到本行的开头位置
换行光标的列坐标不变换到下一行
同时它俩还有一个相同的作用——刷新缓冲区。
例如
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world\r");
sleep(3);
return 0;
}
有的小伙伴可能会好奇为什么没有打印出 "hello world" 呢原因是 "hello world" 其实已经被打印出来了只不过 '\r' 使光标回到了本行开头而机器从光标所在位置向后显示内容所以说 "hello world" 是被覆盖掉了。
至于为什么会显示 [hxy@...] 这一串内容因为这是 Linux 中默认会显示的命令行提示符同样它也是从光标位置开始显示。
再来看看 '\n'
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world\n");
sleep(3);
return 0;
}
到这里我们已经认识了缓冲区与 '\r' '\n'。根据之前的小demo我们可以完成一个简单的进度条小程序了。
3.实现进度条小程序
接下来我们就用刚刚学到的东西完成一个这样的进度条
进度条的实现分为 3 个部分
part1条状加载图案
part2数字加载进度
part3加载动画
part1
part1 部分实现的思路是
1.定义一个数组数组大小看个人喜好但是需要注意预留一个位置给 '/0'
2.循环打印数组的全部内容。每次打印完毕向数组内添加一个字符STYLE造成进度条慢慢变长的效果
3.使用 '\r' 使每次打印数组内容时都能覆盖上次打印的内容。
代码实现
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#define SIZE 101
#define STYLE '/'
void process()
{
char bar[SIZE];
memset(bar,'\0',sizeof(bar));
int i =0;
while(i<=100)
{
printf("[%-100s]\r",bar);
fflush(stdout);
bar[i++] = STYLE;
//每过一秒加载一次
sleep(1);
}
printf("\n");
}
实现效果
part2
part2 部分较为简单只需在上述代码中稍加改动即可。
代码实现
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#define SIZE 101
#define STYLE '/'
void process()
{
char bar[SIZE];
memset(bar,'\0',sizeof(bar));
int i =0;
while(i<=100)
{
printf("[%-100s] [%d%%]\r",bar,i);
fflush(stdout);
bar[i++] = STYLE;
//每过一秒加载一次
sleep(1);
}
printf("\n");
}
实现效果
part3
我们采用循环打印 " | / - \ " 这四个字符来模拟加载动画的效果。
1.定义一个字符数组 char* lable = " | / - \ "
2.用 lable[i%4] 控制打印的内容i%4的作用是控制 i 在区间 [0,3]
代码实现
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#define SIZE 101
#define STYLE '/'
void process()
{
const char* lable = "|/-\\";
char bar[SIZE];
memset(bar,'\0',sizeof(bar));
int i =0;
while(i<=100)
{
printf("[%-100s] [%d%%][%c]\r",bar,i,lable[i%4]);
fflush(stdout);
bar[i++] = STYLE;
//每过一秒加载一次
sleep(1);
}
printf("\n");
}
实现效果
到此为止一个进度条小程序的实现就完成了小伙伴们快实现自己的进度条样式吧。