【linux】Linux第一个小程序-进度条

devtools/2024/10/18 12:19:59/

1. 预备知识:回车和换行

回车(Carriage Return,CR):

  • 在早期的机械打字机中,回车指的是将打字机的打印头移回到行首的操作,这样打印头就可以开始新的一行的打印。
  • 在ASCII编码中,回车用控制字符CR表示,其编码为\r(即十进制的13)。

换行(Line Feed,LF):

  • 换行是指将打印头向下移动到下一行的操作。
  • 在ASCII编码中,换行用控制字符LF表示,其编码为\n(即十进制的10)。

即:回车,回到当前行的行首,不会切换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;
换行,换到当前位置的下一行,而不会回到行首。

在Windows系统中,文本文件的换行符通常是回车加换行(CR+LF,即\r\n)。而在Unix/Linux系统中,换行符仅仅是LF(\n)(Unix/Linux下这个\n就就包括了回车和换行)。

2. 预备知识:缓冲区

#include<stdio.h>
#include<unistd.h>int main()
{printf("hello world!");                                                                                                                                        sleep(3);return 0;
}

在这里插入图片描述

linux下编译运行以上代码,发现在前三秒"hello world!"并未被打印到屏幕上,三秒之后被打印到屏幕上。那么此前三秒,它被储存到了那里呢?
答案是缓冲区,缓冲区(Buffer)主要应用于提高系统性能和效率。缓冲区通常指的是内存中的一段连续区域,用于临时存储数据,减少CPU、内存和外部设备(如硬盘、网络等)之间的交互次数。当应用程序向文件或设备进行读写操作时,数据会首先被存储到缓冲区中,然后再由缓冲区根据特定的刷新策略将数据写入磁盘或设备中。

缓冲区被刷新到显示器上的几种方式:

  • 程序结束的时候,一般要自动冲刷缓冲区
  • \n
  • 缓冲区满了,自动刷新
  • fflush() 函数强制刷新

3. 进度条

此文件夹下新建一个makefile文件:

processbar: Main.c Processbar.cgcc -o $@ $^         //选项 -o $@ 指定输出文件名,其中 $@ 是一个自动变量,代表当前规则的目标(在这里即为processbar)。而 $^ 是另一个自动变量,表示所有依赖文件的集合(即Main.c和Processbar.c).PHONY: clean
clean:rm -f processbar

这是一个用于将Main.cProcessbar.c源文件编译并链接成名为processbar的可执行文件的简单Makefile

这个Makefile提供了两种操作:
1.运行make processbar以编译并链接Main.cProcessbar.c源文件,生成processbar可执行文件。
2.运行make clean以删除processbar可执行文件,清理项目构建产物。

进度条代码版本一:(仅仅是进度条的模拟)

#include <string.h>
#include <unistd.h>
#include<stdio.h>#define Length 101
#define Style '#'   //进度条填充样式为'#'字符
const char* lable="|/-\\";  //在进度条前方显示动画效果void ProcBar();////version 1
void ProcBar()
{char bar[Length];   //进度条的显示长度memset(bar,'\0',sizeof(bar));  //先初始化为'\0'填充清零int len=strlen(lable);int cnt=0;while(cnt<=100)    //使用循环结构,从0迭代到100,每次迭代表示进度的1%{printf("[%-100s][%-3d%%][%c]\r",bar,cnt,lable[cnt%len]);   //用回车并不是换行,每次打印进度条都从当前行头部开始打印fflush(stdout);    //强制刷新标准输出缓冲区,确保进度条立刻显示在屏幕上bar[cnt++]=Style;   //进度条数组bar的相应位置添加进度样式字符usleep(200000);    //用于休眠一段时间,模拟任务执行过程。(休眠单位为微秒)}printf("\n");
}int main()
{ProcBar();return 0;
}

这段C语言代码实现了一个简单的进度条功能,用于模拟某个长时间运行的任务(如文件下载、处理任务等)的进度展示。

效果演示:
在这里插入图片描述

进度条代码版本二:(模拟一个下载任务,根据下载任务的进度打印进度条)

#include <string.h>
#include <unistd.h>
#include<stdio.h>#define Length 101
#define Style '#'   //进度条填充样式为'#'字符
const char* lable="|/-\\";  //在进度条前方显示动画效果void ProcBar();////version 2
////配合场景使用
//进度条每执行一次循环就刷新一次,会出现闪烁(我还挺喜欢这个的)
void ProcBar(double total, double current)    //total代表总任务量(即文件大小),current代表当前已完成的任务量(即已下载的数据量)
{char bar[Length];memset(bar, '\0', sizeof(bar));int len = strlen(lable);int cnt = 0;double rate = (current * 100.0) / total;int loop_count = (int)rate;       //计算进度百分比rate和对应的循环次数loop_countwhile (cnt <= loop_count){printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]);fflush(stdout);bar[cnt++] = Style;//usleep(200000);  //这个也不需要了,在另一个调它的函数download()中有}//printf("\n");
}//模拟下载单个文件
void download()
{double filesize = 100 * 1024 * 1024 * 1.0; // 文件大小100兆double current = 0.0; // 当前下载量double bandwidth = 1024 * 1024 * 1.0; // 网络带宽1兆printf("download begin, current: %lf\n", current);while (current <= filesize)   //使用一个循环来模拟下载过程,每次迭代都更新current的值,并调用ProcBar函数来更新和显示进度条。{// 打印进度条ProcBar(filesize, current);// 从网络获取数据current += bandwidth;usleep(10000);    //模拟网络下载的速度}printf("\ndownload complete!   filesize:%lf\n", filesize);
}int main()
{// 下载测试(模拟单个文件下载)// download();return 0;
}

这段代码实现了一个简单的进度条功能(ProcBar())和一个模拟单个文件下载的函数(download())。实际使用时,只需将download()中的相关参数替换为实际的下载信息,并调用此函数即可在控制台显示下载进度。

效果演示:
在这里插入图片描述

进度条代码版本三:(模拟多个下载任务,根据下载任务的进度打印进度条)

#include <string.h>
#include <unistd.h>
#include<stdio.h>#define Length 101
#define Style '#'   //进度条填充样式为'#'字符
const char* lable="|/-\\";  //在进度条前方显示动画效果typedef void(*callback_t)(double,double);  //函数指针  
void ProcBar();//闪烁版
//void ProcBar(double total, double current)    //total代表总任务量(即文件大小),current代表当前已完成的任务量(即已下载的数据量)
//{
//    char bar[Length];
//    memset(bar, '\0', sizeof(bar));
//    int len = strlen(lable);
//
//    int cnt = 0;
//    double rate = (current * 100.0) / total;
//    int loop_count = (int)rate;       //计算进度百分比rate和对应的循环次数loop_count
//
//    while (cnt <= loop_count)
//    {
//        printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]);
//        fflush(stdout);
//        bar[cnt++] = Style;
//        //usleep(200000);  //这个也不需要了,在另一个调它的函数download()中有
//    }
//
//    //printf("\n");
//}// version 3
// 配合场景使用
// 每次调用函数时直接将bar拼接起来,循环执行完后再刷新,这样就不会出现闪烁
void ProcBar(double total, double current)
{char bar[Length];memset(bar, '\0', sizeof(bar));int len = strlen(lable);int cnt = 0;double rate = (current * 100.0) / total;int loop_count = (int)rate;       //计算进度百分比rate和对应的循环次数loop_countwhile (cnt <= loop_count){bar[cnt++] = Style;}// 填充完成后,一次性打印出完整的进度条,并刷新输出,避免了闪烁现象printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt % len]);fflush(stdout);  
}
//此版本进度条与之前版本不同的是,它在循环中先将进度条字符逐个拼接到bar数组中,待循环完成后一次性刷新输出,从而避免了进度条的闪烁现象。// 模拟下载多个文件
double bandwidth = 1024 * 1024 * 1.0;  // 网络带宽1兆
void download(double filesize, callback_t cb)   // 此处用函数指针也很方便
{double current = 0.0; // 当前下载量printf("download begin, current: %lf\n", current);while (current <= filesize)   //使用一个循环来模拟下载过程,每次迭代都更新当前下载量current,并调用回调函数cb来更新和显示进度条{cb(filesize, current);// 从网络获取数据current += bandwidth;usleep(10000);  //模拟下载速度时,每次迭代都增加bandwidth(网络带宽)的值到current,并使用usleep函数来模拟网络延迟}printf("\ndownload complete!   filesize:%lf\n", filesize);
}int main()
{// 多个文件下载测试download(200 * 1024 * 1024, ProcBar);download(400 * 1024 * 1024, ProcBar);download(50 * 1024 * 1024, ProcBar);download(10 * 1024 * 1024, ProcBar);return 0;
}

这段C代码通过定义一个进度条更新函数ProcBar和一个模拟下载函数download,实现了在控制台中展示动态进度条的功能,并模拟了多个文件的下载过程。通过回调函数的使用,使得download函数可以灵活地与不同的进度条更新函数配合使用。

效果演示:
在这里插入图片描述

闪烁版演示效果:
在这里插入图片描述


http://www.ppmy.cn/devtools/14859.html

相关文章

【AI 测试】分词器

目录 概念分词器种类主要应用场景几种常用的分词器适合用于自然语言处理任务的分词器分词器使用实例概念 分词器(Tokenizer)是一种自然语言处理工具,其核心功能是将连续的自然语言文本切分为一系列有意义的词汇单元。这些词汇单元通常是词或短语,它们在语言学上具有一定的…

服用5年份筑基丹 - React篇

前言 React&#xff0c;作为前端领域的一股强大势力&#xff0c;以其组件化、声明式的编程范式赢得了众多修仙者的青睐。然而&#xff0c;要想真正掌握 React 的精髓&#xff0c;却需要深入骨髓的修炼与理解。这五年的筑基丹&#xff0c;正是我修炼 React 的得力助手。 服下此…

基于51单片机的矩阵按键扫描的proteus仿真

文章目录 一、按键按键按键消抖 二、独立按键仿真图仿真程序 三、矩阵按键仿真图仿真程序 四、总结 一、按键 按键 按键通常指的是电子设备上的一种输入装置&#xff0c;用于在按下时发送信号&#xff0c;以便设备执行相应的操作。按键可以分为独立按键和矩阵按键两种类型。 …

Apache反向代理的功能和設置

Apache反向代理是Apache HTTP伺服器的一種功能&#xff0c;可以讓伺服器接收客戶端的請求並將其轉發到其他伺服器&#xff0c;然後將這些伺服器的回應返回給客戶端。這樣&#xff0c;客戶端就像直接訪問Apache伺服器一樣&#xff0c;而實際上是在訪問其他的伺服器。 Apache反向…

信息收集分类

在信息收集中&#xff0c;需要收集的信息&#xff1a;目标主机的DNS信息、目标IP地址、子域名、旁站和C段、CMS类型、敏感目录、端口信息、操作系统版本、网站架构、漏洞信息、服务器与中间件信息、邮箱、人员、地址等。 信息收集区别 主动信息收集&#xff1a;直接与目标信息发…

Element-plus DatePicker 日期选择器【正则校验时间范围】

效果图&#xff1a; 利用element-plus中的form表单验证完成效果。 <el-form-item label"检查计划截止日期&#xff1a;" prop"deadline"><el-date-pickerv-model"form.deadline"value-format"YYYY-MM-DD"style"width: …

【数据结构】双向链表

目录 1.双向链表的结构 2.双向链表的实现 1.双向链表的初始化 2.尾部插入 3.打印链表 4.头部插入 5.尾删 6.头删 7.查找 8.在指定位置之后插入节点 9.删除指定位置的节点 10.销毁链表 3.顺序表和双向链表的优缺点 1.双向链表的结构 我们观察双向链表的结构可以发现一…

20240309web前端_第四次作业_完成随机点名程序

要求 一、结合抽奖案例完成随机点名程序&#xff0c;要求如下: 1.点击点名按钮&#xff0c;名字界面随机显示&#xff0c;按钮文字由点名变为停止 2.再次点击点名按钮&#xff0c;显示当前被点名学生姓名&#xff0c;按钮文字由停止变为点名 3.样式请参考css及html自由发挥完成…