【Linux系统】Linux入门系统程序−进度条
文章目录
- 一、铺垫知识
- 1.回车符 和 换行符的区别
- 2.用户缓冲区问题
- 二、进度条程序初版(含视频演示效果)
- 三、进度条程序(加入使用场景)
一、铺垫知识
1.回车符 和 换行符的区别
回车符’\r’ 的效果(让光标回到当前行开头) 和 换行符’\n’ 理论上的效果(把光标移动到下一行同一位置):
但实际上单纯的换行作用意义不大,所以在语言层面上,当你单独使用 ‘\n’ 时,它会同时执行回车 + 换行的效果。结论,在语言层面上,使用 ‘\n’ 或 "\r\n"的效果一模一样。
2.用户缓冲区问题
- 执行以下代码观察现象:
#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world");sleep(2);return 0;
}
现象:大约2s后,“hello world” 才被打印到屏幕上。
为什么会出现这种奇怪的现象,代码不是按顺序执行的吗?不应该是先执行printf函数打印,再执行sleep函数休眠吗?
分析:代码肯定是按顺序执行的,出现这种现象实际与用户缓冲区有关。在打印函数与显示器文件之间有一个缓冲区,叫用户缓冲区,printf函数实际上也并不什么打印函数,更确切的说它应该是一种拷贝函数,它会把字符串内容拷贝到用户缓冲区,而当用户缓冲区刷新的时候,用户缓冲区中的内容才会被拷贝到显示器文件(内容被拷贝到显示器文件,用户就能看到内容被打印到显示器的效果)。
用户缓冲区的刷新策略(一般来说是按照行刷新):
(1)遇到 ‘\n’,就会把 ‘\n’ 前的所以内容刷新到显示器文件
(2) 程序结束时,会把用户缓冲区的所有内容刷新到显示器文件
现象解释:printf函数把 “hello world” 拷贝到用户缓冲区中,接着执行sleep函数休眠2s后程序结束,程序结束时用户缓冲区中的所有内容会被刷新到显示器文件。
补充:
sleep函数:让程序休眠指定秒数再向后执行
- 验证第一种用户缓冲区刷新策略:
#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world\n"); // 在结尾加上'\n'换行符sleep(2);return 0;
}
现象:“hello world\n” 瞬间被打印到屏幕上,大约等待2s后程序结束。
结论:字符串结尾加上’\n’之后,字符串内容瞬间就刷新到显示器文件,而不是等待2s程序结束时才刷新,这证明了第一种刷新策略是正确有效的。
- 实际上除了前面两种用户缓冲区的刷新策略之外,系统还为用户提供了一种强制刷新缓冲区的函数:
fflush函数可以强制将用户缓冲区中的内容刷新到显示器文件,
使用方法:fflush(stdout)
C程序在启动的时候,默认打开了3个流:
• stdin - 标准输入流,指键盘文件
• stdout - 标准输出流,指显示器文件
• stderr - 标准错误流
代码验证:
#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world"); // 字符串结尾没加 '\n'fflush(stdout);sleep(2);return 0;
}
现象:“hello world\n” 瞬间被打印到屏幕上,大约等待2s后程序结束。
结论:字符串结尾没加’\n’,字符串内容还是能瞬间就刷新到显示器文件,这证明fflush函数可以强制将用户缓冲区中的内容刷新到显示器文件。
二、进度条程序初版(含视频演示效果)
main.c:
#include "progress.h"int main()
{progress();return 0;
}
progress.h:
#pragma once
#include <stdio.h>
#include <unistd.h>void progress();
progress.c(进度条函数实现):
#include "progress.h"void progress()
{char bar[101] = {'\0'};const char* cnt = "|/-\\"; // '\\'是一个转义字符,⽤于表示⼀个反斜杠,防止它被解释为⼀个转义序列符int count = 0;while(count<=100){printf("[%-100s][%-3d%%][%c]\r",bar,count,cnt[count%4]);fflush(stdout);usleep(50000);bar[count] = '#';count++;}printf("\n");
}
视频演示进度条程序初版代码运行效果(链接: 进度条初版)
补充:
usleep函数:让程序休眠指定微秒数再向后执行
三、进度条程序(加入使用场景)
main.c(模拟下载软件的使用场景:下载函数):
#include "progress.h"void download(double total,double speed) // total:软件总大小;speed:下载速度
{double current_total = 0.0;while(current_total<=total){progress(current_total,total);usleep(10000); // 每隔10000微秒进行一次下载current_total += speed; // 每次下载,进度增加一个下载速度}printf("\n");
}int main()
{printf("程序下载中:\n");download(1024.0,2.0);return 0;
}
progress.h:
#pragma once
#include <stdio.h>
#include <unistd.h>void progress(double,double);
progress.c(进度条函数:进度条不会一次性走完,每次调用进度条函数会打印出当前下载进度):
#include "progress.h"void progress(double current,double total)
{double cur_progress = current/total*100; // 计算出当前进度char bar[101] = {'\0'};int bar_count = (int)cur_progress;for(int i = 0;i < bar_count;i++)bar[i] = '#';const char* cnt = "|/-\\";static int count = 0;printf("[%-100s][%.1lf%%][%c]\r",bar,cur_progress,cnt[count%4]);fflush(stdout);count++;
}