【Linux系统编程】第十四弹---进度条

2024-05-07 13:44

本文主要是介绍【Linux系统编程】第十四弹---进度条,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】

目录

1、回车和换行

2、观察回车换行现象

3、缓冲区

4、usleep和fflush函数

5、简单倒计时

6、进度条

6.1、版本一

6.2、版本二

总结


1、回车和换行

回车:

指光标由行中任意位置移动到行首。

换行:

指换到下一行的情况。

\r:只进行回车

\n:进行回车和换行

2、观察回车换行现象

1.执行下面代码

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

 现象:

打印完字符串,然后休眠3秒,最后结束程序。

2.执行下面代码

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

 现象:

休眠3秒,程序就结束了。

为什么使用\r就不能字符串了呢???

这会牵扯到缓冲区的知识,我们在写一个缓冲区的点来详细讲解!!! 

 补充查询手册:

输入命令:

mam 3 sleep   # 三号手册才能查到我们想用的sleep

3、缓冲区

概念:

在内存中预留了一块空间,用来缓冲输入或输出的数据,这个保留的空间被称为缓冲区。

那为什么字符串结尾有\n就会打印字符串,而有\r则不打印字符串呢???

由于显示器模式是行刷新缓冲区是按行缓冲的。而字符串是先拷贝在内存空间中,当遇到\n的时候,就会强制把字符串刷新到显示器文件上,因此就看到该字符串了。

而字符串后面是\r的情况,不会强制把字符串刷新到显示器,但是当遇到return 0;时,会强制刷新到显示器上,但是由于\r 会回到行首后,会进行覆盖写,shell 提示符会覆盖掉之前写的 “hello world”。

注意:缓冲区满了也会刷新缓冲区。

如果我们想自己手动刷新缓冲区该怎么办呢???

可以通过调用刷新缓冲区的函数,我们在下面通过代码进行讲解。

4、usleep和fflush函数

我们可以通过man手册先查询两个函数的基本用法。

1. usleep函数

功能:

以微秒为间隔暂停执行,头文件为#include<unistd.h>

2.fflush函数

功能:

重刷一个流。

stdout -- 标准输出流 -- 屏幕

stdin -- 标准输入流 -- 键盘

stderr -- 标准错误流 -- 屏幕

3.代码演示

#include<stdio.h>
#include<unistd.h>
int main()
{printf("hello linux\r");fflush(stdout); # 强制刷新输出流sleep(3);       # 休眠3秒return 0;
}

现象:

先打印字符串,然后休眠3秒,字符串被shell提示符覆盖。 

 

5、简单倒计时

 通过上面的简单重刷输出流,我们可以做一个简单的倒计时程序。

要求:实现一个从10到0的倒计时效果。

代码:

#include<stdio.h>
#include<unistd.h>
int main()
{int cnt = 10;while(cnt >= 0){printf("%-2d\r",cnt);// 以2位的固定位宽输出且左对齐方式打印fflush(stdout);//重刷缓冲区sleep(1);//休眠1秒,只有休眠才能看到倒计时的效果cnt--;}printf("\n");return 0;
}

分析:

1. 定义倒计时变量 cnt,让其逐渐递降。
2. 核心就是用 \r 回到缓冲区行首进行覆盖写,然后fflush不断刷新出出来,但是只是刷新并不能看到效果,因为它会直接被覆盖,因此需要休眠一会,几秒自己设置。
3. 格式调整,打印 cnt==10 时,在缓冲区打印的其实是字符1和字符0,如果我们不用 %2d(以2位的固定位宽输出) 来调整格式,而用 d% 的话,那么覆盖写只会覆盖第一位字符 1  的位置,而第二位的字符 0  还留在缓冲区原来的位置,于是倒计时便会变为下面这样
10->90->80->70->60->50->40->30->20->10->00 ,-2d% 加个负号保证其向左对齐。
4. 倒计时完加个 \n符,shell 提示符就不会覆盖倒计时。

6、进度条

6.1、版本一

此处我们安装C语言中的分文件实现此进度条,加上我们Linux中学习的makefile工具。

首先我们创建四个文件:processbar.c  processbar.h  main.c  makefile

processbar.c : 进度条函数的实现。

processbar.h : 进度条函数的声明,头文件包含。

main.c : 调用.h文件中的方法 。

makefile : 自动化编译。

进度条效果:

  • 第一个中括号就是表示进度条。
  • 第二个中括号表示进度。
  • 第三个表示旋转样式。

原理基本跟倒计时一样。

[jkl@VMCentos7 process]$ touch processbar.h processbar.c main.c makefile  # 创建四个文件
[jkl@VMCentos7 process]$ ls
main.c  makefile  processbar.c  processbar.h

 makefile文件代码:

processbar:processbar.c main.cgcc -o $@ $^
.PHONY:clean
clean:rm -f processbar

processbar.h代码:

#includ<stdio.h>
#include<unistd.h>
#include<string.h>void ProcBar();

processbar.c代码:

#include "processbar.h"                                                                                                 //字符串长度
#define Length 101
#define Style '#' //表示进度条的符号const char* label="|/-\\";//两个\\表示一个\,表示旋转样式//version1
void ProcBar()
{char bar[Length];//缓冲区长度 memset(bar,'\0',sizeof(bar));//将缓存区空间都改为\0int len=strlen(label);//字符串长度//循环往缓存区输入#int cnt=0;while(cnt<=100){printf("[%-100s][%3d%%][%c]\r",bar,cnt,label[cnt%len]);fflush(stdout);bar[cnt++]=Style;usleep(30000);//休眠30000微秒,秒太长了}printf("\n");
}

main.c代码:

#include "processbar.h"                                                                                                 int main()
{ProcBar();return 0;
}

运行中的效果: 

 最后的效果:

6.2、版本二

 在我们的实际生活中,进度条一般不会单独出现,常出现在下载界面和游戏界面,因此版本二通过下载场景来进行展示。

 makefile文件代码:

download:download.c test.cgcc -o $@ $^
.PHONY:clean
clean:rm -f download

download.h代码:

#pragma once#include <stdio.h>
#include <string.h>
#include <unistd.h>typedef void(*callback_t)(double, double);//函数指针//void ProcBar();
void ProcBar(double total, double current);

download.c代码:

#include"download.h"#define Length 101
#define Style '='const char *lable = "|/-\\";//version 2
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;while(cnt <= loop_count){bar[cnt++] = Style;//usleep(20000);}printf("[%-100s][%.1lf%%][%c]\r", bar, rate, lable[cnt%len]);fflush(stdout);
}

test.c代码:

​#include"download.h"double bandwidth = 1024*1024*1.0;//download
void download(double filesize,callback_t cb)
{double current = 0.0;printf("download begin, current: %lf\n", current);while(current <= filesize){cb(filesize, current);//从网络中获取数据usleep(100000);current += bandwidth;}printf("\ndownload done, filesize: %lf\n",filesize);
}int main()
{download(100*1024*1024,ProcBar);download(2*1024*1024,ProcBar);return 0;
}

总结


本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

这篇关于【Linux系统编程】第十四弹---进度条的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/967515

相关文章

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Linux命令rm如何删除名字以“-”开头的文件

《Linux命令rm如何删除名字以“-”开头的文件》Linux中,命令的解析机制非常灵活,它会根据命令的开头字符来判断是否需要执行命令选项,对于文件操作命令(如rm、ls等),系统默认会将命令开头的某... 目录先搞懂:为啥“-”开头的文件删不掉?两种超简单的删除方法(小白也能学会)方法1:用“--”分隔命