当前位置: 首页 > news >正文

【Linux】-----进度条小程序

目录

前言

基本知识

Ⅰ、回车和换行

Ⅱ、缓冲区

 两个有意思的现象

简单定义

刷新缓冲区

简易倒计时程序

进度条代码

多文件下makefile写法

一代(无任何场景)

procs1.h代码

procs1.c代码

主函数main1.c

一代运行结果:

二代 (搭配下载场景)

procs2.c代码

procs2.h代码

主函数main2.c 代码

二代结果显示:


前言

前面我们已经学会基本的Linux指令和工具,那么现在来搞个好玩的东西-进度条(简单版本)!!!

基本知识

Ⅰ、回车和换行

首先得明确,回车和换行对于我们而言就是一个简单的动作,可是对于机器来说这是两个独立的动作。

  • 换行

 换行是从末尾位置竖直向下移动一行,此时光标的位置是在下一行的末尾。

  • 回车

 回车是将光标移动到最左侧,也就是文段最开头的位置!

键盘上的回车键是先向下再向左的,对应的就是先换行再回车的两个动作!!

在C语言中,\n是表示回车换行同时,\r仅仅是回车。

Ⅱ、缓冲区

 两个有意思的现象

 ①有‘\n’

代码:

现象:

可以看到,执行这个程序时,先在屏幕上打印对应字符串,休眠3秒后结束程序!

②无‘\n’

代码:

现象:

可以看到这个现象和有‘\n’的不一样,没有'\n'开始运行时并没有打印字符串,而是休眠了3秒,退出程序的同时字符串一起显示出来。。

 对于无‘\n’的现象,我们需要明确一点,程序并不是先休眠了3秒才显示字符串,通俗点来说就是不是先执行sleep函数才去执行printf函数,同样也是先执行printf函数才去执行的sleep函数,因为程序是从上往下依次执行的。那么在这段休眠时间里字符串在哪?被放在了缓冲区里

简单定义

目前我们仅需知道缓冲区实际上就是一块内存空间,对于上面的字符串,就是被保存在这样的一块内存空间里,当程序运行结束时,会自动的刷新缓冲区里的内容到显示器上,所以无‘\n’才能看到上述的现象。

刷新缓冲区

①加上‘\n’,立即刷新

②等待缓冲区满或者程序结束,自动刷新

③强制刷新

怎么强制?

实际上C语言提供了一个的函数--fflush,这个函数就是用于强制刷新缓冲区的。。

这里的文件流后面的文章有详细讲解,现在我们只需要知道程序在运行时默认会打开三种流

  • 标准输入,stdin
  • 标准输出,stdout
  • 标准错误,stderr

我们的显示器就是标准输出文件,Linux下一切皆文件!所以可以采用该函数强制刷新到对应的文件流上。

演示:

 代码:

现象:

可以看到,即使程序没有‘\n’,也能直接显示字符串内容!!

有了上面的知识可以先来实现一个简单的倒计时程序

简易倒计时程序

 原理:实际就是对同一个位置进行覆盖进而实现一个动态的效果。

每当显示一个数字之后就将光标挪动至最前面(回车),休眠,然后再显示下一个数字。回车配休眠需要强制刷新缓冲区。

代码:

1 #include <stdio.h>2 #include <unistd.h>3 4 int main()5 {6   int cnt=10;7 8   while(cnt>=0)9   {10     printf("倒计时:%2d\r",cnt);11 12     fflush(stdout);//强制刷新到屏幕13     sleep(1);                                                                                                                                                           14     cnt--;15   }16   return 0;17 }

注意:为什么用%2d,是因为数字显示在屏幕上时,实际上是字符串的形式,相当于10是两个字符的字符串,需要覆盖两个字符。当然,大家感兴趣把2去掉看看! 

结果如下:

进度条代码

这里采用多文件的形式去实现的,为了更加方便的去管理代码。

多文件下makefile写法

一代(无任何场景)

procs1.h代码

主要是头文件的包含以及函数的声明!

#pragma once                                                                                                
#include <stdio.h>                                                                
#include <string.h>                                                                    
#include <unistd.h>                                                                                      void processbar1();     

procs1.c代码

主功能实现

代码如下:

#include "procs.h"#define Length 101 //进度条长度
#define Style '|' //进度条样式
const char* lab="|/-\\";//加载旋转光标
void processbar1()
{char bar[Length];//字符数组memset(bar,'\0',sizeof(bar));//初始化为\0int cnt=0;while(cnt<=100){printf("[%-100s][%3d%%][%c]\r",bar,cnt,lab[cnt%strlen(lab)]);//\r为了完成覆盖                                                                                       fflush(stdout); //强制刷新bar[cnt++]=Style;//字符追加至数组中usleep(100000);}printf("\n");}

代码解释:

①根据上述的效果图,进度条实际上是放在一个数组的中,所以定义一个长度为101的字符数组。数组按字节全部初始化为'\0'!

②因为要带来动态的效果所以运用上面提到的倒计时程序类似。回车('\r')配延时,强制刷新缓冲区

③%-100s:表示左对齐

④%3d%%:最后的双百分号,是为了取字面值%,以实现100%的效果。因为单独一个%在C语言中有着特殊含义。

const char* lab:字符串,同样最后的”\\“,也是为了取字面值\,防止转义,单独的\在C语言有着特殊含义。

⑥lab[cnt%strlen(lab)]:取模操作是为了防止数组越界!

主函数main1.c

调用函数即可。

 

一代运行结果:

二代 (搭配下载场景)

进度条不可能单独存在,一般常见的场景就是下载这一场景,会根据网络带宽,文件大小等其他的要素来决定下载进度,当然哦这里只是简单的模拟一下,没有涉及从网络获取数据等其他相关知识。

procs2.c代码

这里的改进主要是函数头包含了文件的总大小以及当前的下载进度。根据进度打印进度条!

#include "procs.h"#define Length 101 //进度条长度
#define Style '|' //进度条样式
const char* lab="|/-\\";//加载旋转标志
void processbar2(double total,double current)
{                                                                                                                                                                       char bar[Length];memset(bar,'\0',sizeof(bar));//初始化为\0int len=strlen(lab);int cnt=0;double rate=(current*100.0)/total;//计算比率int load_top=(int)rate;while(cnt<=load_top){bar[cnt++]=Style;//字符追加至数组中}printf("[%-100s][%.1lf%%][%c]\r",bar,rate,lab[cnt%len]);//\r为了完成覆盖fflush(stdout); //强制刷新
}

解释一下:

①因为主函数的下载功能是一个循环,会不断的调用该功能函数,每次的下载进度都不一样,因此需要计算每次的比率,再根据比率去打印进度条。。

②这里和一代的不同就是循环体,这里是先将字符一次性放进数组中,最后在一起刷新出来。如果不这样的话每次都会显示从0开始打印,并不是我们想看到的结果。。不信,你可以试试按照一代的写法。。

procs2.h代码

#pragma once #include <stdio.h>
#include <string.h>
#include <unistd.h>
typedef void(*Call_back)(double,double);//定义函数指针类型,为了方便回调                                                                                                    
void processbar2(double total,double current);

注意:这里声明了一个Call_back函数指针类型目的就是实现函数回调。因为未来可能还有更多版本的进度条功能代码, 采用函数指针的方式,只需要传入对应的函数名,就会去调用对应的功能代码。

主函数main2.c 代码

#include "procs.h"                                                    double bandwith=1024*1024*1.0;//下载速度1MB/s                         void download(double filesize,Call_back cb)//函数指针做参数                         
{                                                                     double cnt=0.0;                                                     printf("download begin....,bandwith is:%.1lf\n",bandwith);          while(cnt<=filesize)                                                {                                                                   cb(filesize,cnt);                                                 usleep(100000);                                                   cnt+=bandwith;                                                    }                                                                   printf("\ndownload finishi......,filesize is:%.1lf\n",filesize);    printf("\n");                                                       
}                                                                     
int main()                                                            
{                                                                     download(50.0*1024*1024,processbar2);//50MB                         download(10.0*1024*1024,processbar2);//10MB                        download(100.0*1024*1024,processbar2);//100MB                                                                                                                         return 0;
}

如代码,下载功能存在一个函数指针类型的参数,只需传入函数名(函数地址),就能找到对应函数的功能实现,效率极高也十分的巧妙。

二代结果显示:

可以看到,进度条会根据文件大小的不同,下载的速度也不一样,同一带宽情况下,文件越大,那必然越慢,如上图的10MB比100MB快多了。。

二代的场景更加贴近实际哦!!


 好了,今天的分享就到这里,如果对你有帮助,欢迎三连!!!

相关文章:

【Linux】-----进度条小程序

目录 前言 基本知识 Ⅰ、回车和换行 Ⅱ、缓冲区 两个有意思的现象 简单定义 刷新缓冲区 简易倒计时程序 进度条代码 多文件下makefile写法 一代(无任何场景) procs1.h代码 procs1.c代码 主函数main1.c 一代运行结果&#xff1a; 二代 (搭配下载场景) procs2.c代…...

普通人有必要学Python吗?学了之后能做什么?

目录 首先来说一下极其推荐的方向&#xff1a; 1、数据分析 2、科学计算 3、大数据框架 4、脚本开发 5、爬虫 6、Web框架 总结&#xff1a; 如果你还没有开始使用Python&#xff0c;答应我&#xff0c;把这个回答看完&#xff0c;如果你真的学习并深入使用过Python&…...

2023-2024年 Java开发岗面试题经验分享

在各行各业中&#xff0c;面试前我们总会思索一个问题&#xff1a;究竟什么样的求职者能获得面试官的青睐&#xff1f;作为求职者&#xff0c;我们又该如何准备&#xff0c;以应对各种面试官的挑战&#xff1f;在这激烈的竞争里&#xff0c;如何才能让自己从众多应聘者中脱颖而…...

JavaScript中URL和Blob

JavaScript中URL和Blob 常用于处理文件数据、图像数据、音频数据等。Blob对象通常用于在客户端处理文件&#xff0c;如上传文件、下载文件、处理图像等操作。Blob对象可以通过Blob构造函数创建&#xff0c;也可以通过其他方式获取&#xff0c;比如从File对象中获取。 使用场景…...

平舌、翘舌音学习: z、c、s--zh、ch、sh

平舌音翘舌音不分怎么办&#xff1f; 尝试整理了&#xff0c;如下一些材料&#xff1a; 一、 策略篇&#xff1a; 一年级拼音如何区分掌握&#xff1a;平舌音和翘舌音&#xff1f; 喜马拉雅&#xff0c; 平舌音翘舌音教学&#xff1a;普通话声母zh以及zh ch sh与z c s的发音练…...

Windows(Win10、Win11)本地部署开源大模型保姆级教程

目录 前言1.安装ollama2.安装大模型3.安装HyperV4.安装Docker5.安装聊天界面6.总结 点我去AIGIS公众号查看本文 本期教程用到的所有安装包已上传到百度网盘 链接&#xff1a;https://pan.baidu.com/s/1j281UcOF6gnOaumQP5XprA 提取码&#xff1a;wzw7 前言 最近开源大模型可谓闹…...

快速排序(下)

快速排序&#xff08;下&#xff09; 前言 在上一篇文章中我们了解了快速排序算法&#xff0c;但那是Hoare的版本&#xff0c;其实还有别的版本&#xff1a;一种是挖坑法&#xff0c;它们的区别主要在于如何找基准值。霍尔的版本思路难理解但代码好理解&#xff0c;挖坑法则是…...

LazyLLM:长上下文场景下提高LLM推理效率

LazyLLM旨在优化大型语言模型&#xff08;LLM&#xff09;在处理长文本语境下的推理效率。传统上&#xff0c;LLM的推理过程分为预填充和解码两个阶段&#xff0c;其中预填充阶段负责计算并存储输入提示的所有token的键值&#xff08;KV&#xff09;缓存&#xff0c;这一步骤在…...

PDF文件点击打印无反应?是何原因造成能解决吗?

PDF无法打印怎么处理&#xff1f;在我们工作中&#xff0c;经常会遇见各种各样的文件问题&#xff0c;当我们想要将PDF文件打印出来纸质版使用&#xff0c;却不知什么原因&#xff0c;显示PDF无法打印&#xff0c;这时应该怎么处理呢&#xff1f; 一般情况下&#xff0c;PDF文件…...

初学者友好!从零到一快速上手PyCharm安装的超详细图解+避坑指南教程

一&#xff0c;pycharm的官网下载 下载地址&#xff1a;www.jetbrains.com/pycharm/ 本文将从 Python解释器安装到Pycharm专业版安装和配置汉化等使用都进行了详细介绍&#xff0c;希望能够帮助到大家。 Python解释器&Pycharm安装包&Pycharm破姐插件我都打包好了。 …...

AI大模型需要什么样的数据?

数据将是未来AI大模型竞争的关键要素 人工智能发展的突破得益于高质量数据的发展。例如&#xff0c;大型语言模型的最新进展依赖于更高质量、更丰富的训练数据集&#xff1a;与GPT-2相比&#xff0c;GPT-3对模型架构只进行了微小的修改&#xff0c;但花费精力收集更大的高质量…...

Java每日一练_模拟面试题1(死锁)

一、死锁的条件 死锁通常发生在两个或者更多的线程相互等待对方释放资源&#xff0c;从而导致它们都无法继续执行。死锁的条件通常被描述为四个必要条件&#xff0c;也就是互斥条件、不可剥夺条件、占有并等待条件和循环等待条件。 互斥条件&#xff1a;资源不能被共享&#x…...

第三方库认识- Mysql 数据库 API 认识

文章目录 一、msyql数据库API接口1.初始化mysql_init()——mysql_init2.链接数据库mysql_real_connect——mysql_real_connect3.设置当前客户端的字符集——mysql_set_character_set4.选择操作的数据库——mysql_select_db5.执行sql语句——mysql_query6.保存查询结果到本地——…...

Python兼职接单全攻略:掌握技能,拓宽收入渠道

引言 随着Python在数据处理、Web开发、自动化办公、爬虫技术等多个领域的广泛应用&#xff0c;越来越多的人开始利用Python技能进行兼职接单&#xff0c;以此拓宽收入渠道。本文将详细介绍Python兼职接单的注意事项、所需技能水平、常见单子类型、接单途径及平台&#xff0c;帮…...

一键编译并启动一个 ARM Linux qemu 虚拟机

需要事先自己编译 qemu-system-arm 可执行文件&#xff1b; 1&#xff0c;编译创建ARM 虚拟机 #!/usr/bin/bash sudo lssudo apt-get install gcc-arm-linux-gnueabi#wget https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.gztar zxf linux-kernel-v5.10…...

KubeVirt虚拟机存储及网络卸载加速解决方案

1. 方案背景 1.1. KubeVirt介绍 随着云计算和容器技术的飞速发展&#xff0c;Kubernetes已成为业界公认的容器编排标准&#xff0c;为用户提供了强大、灵活且可扩展的平台来部署和管理各类应用。然而&#xff0c;在企业的实际应用中&#xff0c;仍有许多传统应用或遗留系统难…...

JVM—对象已死?

参考资料&#xff1a;深入理解Java虚拟机&#xff1a;JVM高级特性与最佳实践&#xff08;第3版&#xff09;周志明 在堆里面存放着 Java 世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。 1、如何判…...

【前端面试3+1】20 css三栏布局6种实现方式、多行文本溢出怎么实现、token过期了怎么处理、【二叉树的中序遍历】

一、css三栏布局6种实现方式 1.浮动布局&#xff08;Floats&#xff09; .container {overflow: auto; /* 清除浮动 */ }.left, .right {width: 20%; /* 左右栏宽度 */float: left; }.middle {width: 60%; /* 中间栏宽度 */margin: 0 20%; /* 左右栏宽度 */ } 2.Flexbox .conta…...

【C++】vector介绍以及模拟实现(超级详细<=>源码并存)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 【C】vector介绍以及模拟实现 前言vector介绍 vector常见操作构造函数iteratorcapacitymodify vector模拟实现存储结构默认构造函数构造函数拷贝构造函数赋值运算符重载析构函数 容量&#xff08;capacity&#xff09;si…...

【Redis 进阶】主从复制(重点理解流程和原理)

在分布式系统中为了解决单点问题&#xff08;某个服务器程序只有一个节点&#xff08;只搞一个物理服务器来部署这个服务器程序&#xff09;。可用性不高&#xff1a;如果这个机器挂了意味着服务就中断了&#xff1b;性能 / 支持的并发量比较有限&#xff09;。通常会把数据复制…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...

FOPLP vs CoWoS

以下是 FOPLP&#xff08;Fan-out panel-level packaging 扇出型面板级封装&#xff09;与 CoWoS&#xff08;Chip on Wafer on Substrate&#xff09;两种先进封装技术的详细对比分析&#xff0c;涵盖技术原理、性能、成本、应用场景及市场趋势等维度&#xff1a; 一、技术原…...

02-性能方案设计

需求分析与测试设计 根据具体的性能测试需求&#xff0c;确定测试类型&#xff0c;以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通&#xff0c;初步确定压测方案及具体的性能指标QA完成性能测试设计后&#xff0c;需产出测试方案文档发送邮件到项目组&…...

Centos 7 服务器部署多网站

一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站&#xff0c;目录结构如下&#xff1a; bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…...

python数据结构和算法(1)

数据结构和算法简介 数据结构&#xff1a;存储和组织数据的方式&#xff0c;决定了数据的存储方式和访问方式。 算法&#xff1a;解决问题的思维、步骤和方法。 程序 数据结构 算法 算法 算法的独立性 算法是独立存在的一种解决问题的方法和思想&#xff0c;对于算法而言&a…...