【linux】进度条
🔥个人主页:Quitecoder
🔥专栏:linux笔记仓
目录
- 01.屏幕缓冲区
- 换行(LF, `\n`)和回车(CR, `\r`)
- 换行回车在屏幕缓冲区中的作用
- 代码块1:
- 代码块2:
- 02.进度条
- 优化版本
01.屏幕缓冲区
屏幕缓冲区是指在输出设备(如终端或控制台)之前,数据被存储的内存区域。应用程序将输出数据写入这个缓冲区,然后系统统一将缓冲区的内容刷新到屏幕上。缓冲区的使用提高了I/O操作的效率,因为它允许数据批量刷新,而不是每次输出都进行一次I/O操作。
缓冲区刷新模式:
缓冲区的刷新模式决定了什么时候会将缓冲区内容刷新到终端屏幕上。主要有以下几种模式:
-
全缓冲模式(Fully Buffered):
- 数据只有在缓冲区满时才会被刷新到屏幕上。通常用于文件I/O。
-
行缓冲模式(Line Buffered):
- 当遇到换行字符(LF,
\n
)时,缓冲区内容会被刷新到屏幕上。常见于终端I/O。 - 一些标准输出流(如
stdout
)在连接到终端时默认使用行缓冲模式。
- 当遇到换行字符(LF,
-
无缓冲模式(Unbuffered):
- 数据每次写入缓冲区后立即被刷新到屏幕上。适用于需要实时输出的场景,如错误输出流(如
stderr
)通常是无缓冲的。
- 数据每次写入缓冲区后立即被刷新到屏幕上。适用于需要实时输出的场景,如错误输出流(如
换行(LF, \n
)和回车(CR, \r
)
在屏幕缓冲区的刷新以及终端输出中,换行字符和回车字符有着重要的作用:
-
换行(Line Feed,
\n
):- 功能:将光标移到下一行。
- 在行缓冲模式下:
- 当输出流遇到换行字符时,缓冲区的内容会被立即刷新到屏幕上,从而实现行缓冲的机制。
- 在许多现代终端和编程环境中,输出一个换行字符通常意味着会将当前行的数据刷新到屏幕。
-
回车(Carriage Return,
\r
):- 功能:将光标移动到当前行的起始位置(即行首),但不移动到下一行。
- 用途:
- 常用于覆盖同一行内容,如进度条或动态日志输出。输出回车字符后,下一次的输出会从行首开始,覆盖当前行的内容。
换行回车在屏幕缓冲区中的作用
-
行缓冲模式:换行字符(
\n
)会触发缓冲区刷新,将内容显示到屏幕上。 -
回车字符(
\r
):不触发缓冲区刷新,而是移动光标,通常与手动刷新缓冲区结合使用,以实现动态行更新。 -
缓冲区刷新模式(全缓冲、行缓冲和无缓冲)控制了何时将数据从缓冲区刷新到屏幕。
-
换行字符(
\n
)在行缓冲模式下起到触发缓冲区刷新的作用,同时将光标移到下一行。 -
回车字符(
\r
)将光标移动到行首,常用于覆盖当前行的内容,而不触发缓冲区刷新。 -
综合使用换行和回车字符,可以实现灵活的终端输出效果,特别在实时显示和动态更新场景中非常常见。
从您提供的代码来看,您有两个几乎相同的代码块,但你希望了解的现象可能是与终端缓冲和输出可见性相关的。让我们总结并推测可能的观察现象。
代码块1:
#include <stdio.h>
#include <unistd.h> // For sleep()
int main() {
printf("hello Makefile!\n");
sleep(3);
return 0;
}
代码块2:
#include <stdio.h>
#include <unistd.h> // For sleep()
int main() {
printf("hello Makefile!");
sleep(3);
return 0;
}
终端输出现象
代码块1:
printf("hello Makefile!\n");
- 输出字符串 “hello Makefile!” 后接换行符
\n
。 - 在行缓冲模式下,遇到
\n
立即刷新输出缓冲区内容到终端。 - 您会立即看到 “hello Makefile!” 和换行,接下来程序会暂停3秒钟,然后退出。
终端显示:
hello Makefile!
(暂停3秒钟)
代码块2:
printf("hello Makefile!");
- 输出字符串 “hello Makefile!”,但没有换行符
\n
。 - 在行缓冲模式下,由于没有遇到
\n
,缓冲区不立即刷新到终端,除非缓冲区满或者进程结束。 - 因为接下来代码调用
sleep(3)
而没有刷新缓冲区,所以在大多数情况下,您在终端上可能看不到立即的输出。 - 直到程序退出或缓冲区被手动刷新,“hello Makefile!” 的内容才会显示。
终端显示:
(暂停3秒钟)
hello Makefile!
如果你希望在没有换行符的情况下立即刷新输出缓冲区,可以在 printf
后调用 fflush(stdout)
:
修改后的代码块2:
#include <stdio.h>
#include <unistd.h>
int main() {
printf("hello Makefile!");
fflush(stdout); // 手动刷新标准输出缓冲区
sleep(3);
return 0;
}
这样做确保 “hello Makefile!” 会立即显示在终端上,不需要等到程序退出或缓冲区满。
终端显示:
hello Makefile!
(暂停3秒钟)
- 带有换行符
\n
的printf
在行缓冲模式下会立即刷新到终端。 - 没有换行符的
printf
可能不会立即刷新缓冲区,需要手动调用fflush(stdout)
。 - 使用
\n
或fflush(stdout)
确保输出立即可见,尤其是在待运行一段时间的代码(如sleep()
)之后进行输出时。
这些现象主要源于终端缓冲机制的行为,在不同开发和调试环境中(特别是高速输出场景下)理解这些机制尤其有用。
02.进度条
有了上面缓冲区的知识,我们就可以实现一个简易版的进度条
文件结构如下
准备工作完成后,我们下面只需完成进度条的主体代码即可
#include"Processbar.h"
#include<string.h>
#include<unistd.h>
#define length 101
#define Style '#'
void Procbar()
{
char bar[101];
memset(bar,'\0',sizeof(bar));
int cnt=0;
while(cnt<=100)
{
printf("[%-100s][%d%%]\r",bar,cnt);
fflush(stdout);
bar[cnt++]=Style;
usleep(10000);
}
printf("\n");
}
进度条显示函数 Procbar
:
char bar[length];
:声明一个字符数组bar
,长度为length
(101 个字符),用于存储进度条的内容。memset(bar, '\0', sizeof(bar));
:将bar
数组的所有元素初始化为\0
,表示进度条初始为空。int cnt = 0;
:初始化一个整型变量cnt
,作为进度百分比,从0开始。while(cnt <= 100)
:使用while
循环,将cnt
从0逐步增到100,模拟从0%到100%的进度条显示。printf("[%-100s][%d%%]\r", bar, cnt);
:格式化输出进度条。%-100s
表示左对齐,宽度为100的字符串,%d%%
表示当前的百分比。\r
让光标返回行首。fflush(stdout);
:刷新标准输出,使得进度条及时更新。bar[cnt++] = Style;
:将bar
数组的第cnt
个位置设置为#
,并将cnt
递增1,表示进度条推进一格。usleep(10000);
:暂停程序10毫秒,以模拟进度条的动态效果。
printf("\n");
:循环结束后,打印一个换行符,结束进度条的显示。
优化版本
我们设置文件大小和带宽速度,这时候进度条的函数需要进行修改
1 #include"Processbar.h"
2 #include<unistd.h>
3
4 void download()
5 {
6 double filesize=100*1024*1024*1.0;
7 double current=0.0;
8 double bandwidth=1024*1024*1.0;
9 printf("download begin,current: %lf\n",current);
10 while(current<=filesize)
11 {
12 Procbar(filesize,current);
13 current+=bandwidth;
14 usleep(10000);
15 }
16
17 printf("\ndownload done ,filesize: %lf\n",filesize);
18 }
19 int main()
20 {
21 // download();
22 // Procbar(100.0,69.0);
23 download();
24 return 0;
25 }
1 #include"Processbar.h"
2 #include<string.h>
3 #include<unistd.h>
4
5 #define length 101
6 #define Style '#'
7
8 void Procbar(double total,double current)
9 {
10 char bar[101];
11
12 memset(bar,'\0',sizeof(bar));
13 int cnt=0;
14 double rate = (current*100.0)/total;
15 int loop_count =(int)rate;
16
17 while(cnt<=loop_count)
18 {
19 bar[cnt++]=Style;
20 }
21 printf("[%-100s][%.1lf%%]\r",bar,rate);
22 fflush(stdout);
23 }