【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 一代运行结果: 二代 (搭配下载场景) procs2.c代…...

普通人有必要学Python吗?学了之后能做什么?
目录 首先来说一下极其推荐的方向: 1、数据分析 2、科学计算 3、大数据框架 4、脚本开发 5、爬虫 6、Web框架 总结: 如果你还没有开始使用Python,答应我,把这个回答看完,如果你真的学习并深入使用过Python&…...

2023-2024年 Java开发岗面试题经验分享
在各行各业中,面试前我们总会思索一个问题:究竟什么样的求职者能获得面试官的青睐?作为求职者,我们又该如何准备,以应对各种面试官的挑战?在这激烈的竞争里,如何才能让自己从众多应聘者中脱颖而…...
JavaScript中URL和Blob
JavaScript中URL和Blob 常用于处理文件数据、图像数据、音频数据等。Blob对象通常用于在客户端处理文件,如上传文件、下载文件、处理图像等操作。Blob对象可以通过Blob构造函数创建,也可以通过其他方式获取,比如从File对象中获取。 使用场景…...
平舌、翘舌音学习: z、c、s--zh、ch、sh
平舌音翘舌音不分怎么办? 尝试整理了,如下一些材料: 一、 策略篇: 一年级拼音如何区分掌握:平舌音和翘舌音? 喜马拉雅, 平舌音翘舌音教学:普通话声母zh以及zh ch sh与z c s的发音练…...

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

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

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

PDF文件点击打印无反应?是何原因造成能解决吗?
PDF无法打印怎么处理?在我们工作中,经常会遇见各种各样的文件问题,当我们想要将PDF文件打印出来纸质版使用,却不知什么原因,显示PDF无法打印,这时应该怎么处理呢? 一般情况下,PDF文件…...

初学者友好!从零到一快速上手PyCharm安装的超详细图解+避坑指南教程
一,pycharm的官网下载 下载地址:www.jetbrains.com/pycharm/ 本文将从 Python解释器安装到Pycharm专业版安装和配置汉化等使用都进行了详细介绍,希望能够帮助到大家。 Python解释器&Pycharm安装包&Pycharm破姐插件我都打包好了。 …...

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

Java每日一练_模拟面试题1(死锁)
一、死锁的条件 死锁通常发生在两个或者更多的线程相互等待对方释放资源,从而导致它们都无法继续执行。死锁的条件通常被描述为四个必要条件,也就是互斥条件、不可剥夺条件、占有并等待条件和循环等待条件。 互斥条件:资源不能被共享&#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开发、自动化办公、爬虫技术等多个领域的广泛应用,越来越多的人开始利用Python技能进行兼职接单,以此拓宽收入渠道。本文将详细介绍Python兼职接单的注意事项、所需技能水平、常见单子类型、接单途径及平台,帮…...

一键编译并启动一个 ARM Linux qemu 虚拟机
需要事先自己编译 qemu-system-arm 可执行文件; 1,编译创建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介绍 随着云计算和容器技术的飞速发展,Kubernetes已成为业界公认的容器编排标准,为用户提供了强大、灵活且可扩展的平台来部署和管理各类应用。然而,在企业的实际应用中,仍有许多传统应用或遗留系统难…...

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

【前端面试3+1】20 css三栏布局6种实现方式、多行文本溢出怎么实现、token过期了怎么处理、【二叉树的中序遍历】
一、css三栏布局6种实现方式 1.浮动布局(Floats) .container {overflow: auto; /* 清除浮动 */ }.left, .right {width: 20%; /* 左右栏宽度 */float: left; }.middle {width: 60%; /* 中间栏宽度 */margin: 0 20%; /* 左右栏宽度 */ } 2.Flexbox .conta…...
【C++】vector介绍以及模拟实现(超级详细<=>源码并存)
欢迎来到我的Blog,点击关注哦💕 【C】vector介绍以及模拟实现 前言vector介绍 vector常见操作构造函数iteratorcapacitymodify vector模拟实现存储结构默认构造函数构造函数拷贝构造函数赋值运算符重载析构函数 容量(capacity)si…...

【Redis 进阶】主从复制(重点理解流程和原理)
在分布式系统中为了解决单点问题(某个服务器程序只有一个节点(只搞一个物理服务器来部署这个服务器程序)。可用性不高:如果这个机器挂了意味着服务就中断了;性能 / 支持的并发量比较有限)。通常会把数据复制…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...