初识Linux · 进度条

2024-09-07 22:52
文章标签 linux 初识 进度条

本文主要是介绍初识Linux · 进度条,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言:

1 缓冲区和回车换行

2 进度条


前言:

我们目前学习了些许知识,已经足够支持我们写一个非常非常小的项目了,即进度条,相信大家都有过下载游戏,等待游戏更新完成的时候,那么此时就有一个进度条,代表着游戏的更新进度,那么我们今天就来模拟实现这个过程,在此之前,我们需要一些预备知识。


1 缓冲区和回车换行

回车换行?是的,你没有看错,相信不少人对换行有一定的误解,我们在C语言里面使用的\n,代表的就是换行,换行之后,不少人发现光标都移动到下一行的最开始,所以不少人认为换行就是直接到下一行的开始,但是实际上并不是这样的,我们不妨看一下老式的键盘:

可以看到,回车是由一个L形状的,结合我们的语文作文,每次一行写满了,需要写下一行的时候,我们总是先定位到下一行,再回退到最开始,从当前位置定位到下一行的这个动作,就代表的是换行,从当前行的位置回退到最开始的位置的这个动作,就叫做回车,此时肯定有人会想到C语言的\r,代表的正是回车:

printf("%r",...);

当\n和\r在一起的时候,\n才是换行,其他时候都是回车换行,今天,我们学习的进度条的项目,就是使用的是\r这个占位符,即光标回退,执行覆盖的操作。

那么现在再来看看一段代码:

  1 #include <stdio.h>2 #include <unistd.h>3 int main()4 {5   printf("Hello Linux!");                                                 6   sleep(1);7   return 0;8 }

这是在Linux中运行的一段代码,我们在Hello Linux!后面加\n和不加\n是有区别的,当我们没有\n,系统是先休眠一秒钟,然后打印Hello Linux!,但是我们如果在Hello Linux!后面加上了\n,就会先打印Hello Linux!,然后再进行休眠,这个现象不明显,但是可以引出比较重大的问题。

首先,缓冲区是什么?我们不妨将缓冲区认定为一块内存空间,在C++的学习中我们知道\n是刷新缓冲区的标志,所以,当我们没有加\n,printf先将字符串输入到缓冲区,然后等待刷新,此时没有刷新标志,所以系统执行sleep函数,休眠了1秒,此时程序结束,强制刷新缓冲区,所以现象是先休眠再打印,那么有了\n就同理,直接打印再休眠就完事了。

那么为什么强制刷新一定是在程序结束了再强制的呢?为什么不能提前强制刷新,当然是可以的,我们使用函数fflush即可:

我们可以看到参数是文件指针,那么我们去哪里找呢?

不要忘了,系统是默认打开了三个流,分别是stdin stdout stderror,文件输出流就是stdout,那么为什么是默认打开的?

因为早期的时候,发明编译器的人看到这么多人都有相同的需求,所以就有了后面的默认打开三个流。

那么此时代码就变成:

  1 #include <stdio.h>2 #include <unistd.h>3 int main()4 {5   printf("Hello Linux!");6   fflush(stdout);                                                         7   sleep(1);8   return 0;9 }

现象就变成了先打印,然后再sleep,这就是强制刷新。

当然了,不用强制刷新想要验证缓冲区也很简单,我们只需要在Hello部分加上\n,看打印效果就可以了->打印效果就是先打印Hello然后再打印Linux。

有人就会提问了,为什么非要用\n来表示刷新标志呢?

\n刷新,简称行刷新,我们从缓冲区刷新到显示器文件上,要求的应该是少次数多数据量,最初的那批人结合了很多方面,觉得行刷新是最合适的,既要中和次数,也要考虑数据量的问题,所以选中了\n。


2 进度条

有了以上的基础,我们现在来实现一下进度条。

  1 #pragma once 2 #include <stdio.h>3 #include <string.h>4 #include <unistd.h>5 6 #define LENGTH 1017 #define style '='8 const char* lable = "|/-\\";9 10 void processbar()11 {12   char arr[LENGTH];13   memset(arr,'\0',sizeof(arr));14   int len = strlen(lable);15   int cnt = 0;16   while(cnt <= 100)17   {18     printf("[%-100s][%3d%%][%c]\r",arr,cnt,lable[cnt%len]);19     fflush(stdout);  // -> 不加导致卡顿20     arr[cnt++] = style;21     usleep(20000);22 23   }24   printf("\n"); // 不换行会导致命令提示符覆盖进度条                                                                                                                                                           25 }

本身代码是比较简单的,这里要注意两个点,一个是如果不强制刷新,也能达到我们想要的效果,但是是会等usleep休眠完了再打印,所以相对来说是有点卡顿的。

如果最后没有\n,就会导致命令提示符覆盖我们想要的进度条,从而导致覆盖,如:

上面的是正常的,下面的就是没有加,从而导致出现错误。

还有一个小点是要表达%需要加上两个%,就像两个\一样的,防止被转义了。

但是这个进度条版本并不逼真,总不可能什么东西都没有,咱们就干巴巴的来个进度条吧?

所以我们实现第二个版本,加点修饰什么的:

typedef void(*callback_t)(double,double);                                                            
void processbar(double total,double current)                                                        
{                                                                                                    char arr[LENGTH];                                                                                 memset(arr,'\0',sizeof(arr));                                                                     double rate = (current * 100.0) / total;                                                           int loop_rate = (int)rate;                                                                         int len = strlen(lable);                                                                           int cnt = 0;                                                                                       while(cnt <= loop_rate)                                                                            arr[cnt++] = style;                                                                              printf("[%-100s][%3.1lf%%][%c]\r",arr,rate,lable[cnt%len]);                                        fflush(stdout);                                                                                   }                                                                                                    

在进度条的头文件里面,我们稍加修饰,在主函数里面也一样:

  3 void Down_load(double filesize,callback_t cb)                                                                                                          4 {                                                                                                          5   double current = 0,bandtwidth = 1024*1024;                                                                                                                                                                  6   printf("Download begin...\n");                                                                                                          7   while(current <= filesize)                                                                                                          8   {                                                                                                          9     cb(filesize,current);                                                                                                          10     usleep(20000);                                                                                                          11     current += bandtwidth;                                                                                                          12   }                                                                                                          13   printf("Download done...\n");                                                                                                          14 } 

此时进度条的最简易版本就出来了。


感谢阅读!

这篇关于初识Linux · 进度条的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Linux Mint Xia 22.1重磅发布: 重要更新一览

《LinuxMintXia22.1重磅发布:重要更新一览》Beta版LinuxMint“Xia”22.1发布,新版本基于Ubuntu24.04,内核版本为Linux6.8,这... linux Mint 22.1「Xia」正式发布啦!这次更新带来了诸多优化和改进,进一步巩固了 Mint 在 Linux 桌面

Python中实现进度条的多种方法总结

《Python中实现进度条的多种方法总结》在Python编程中,进度条是一个非常有用的功能,它能让用户直观地了解任务的进度,提升用户体验,本文将介绍几种在Python中实现进度条的常用方法,并通过代码... 目录一、简单的打印方式二、使用tqdm库三、使用alive-progress库四、使用progres

LinuxMint怎么安装? Linux Mint22下载安装图文教程

《LinuxMint怎么安装?LinuxMint22下载安装图文教程》LinuxMint22发布以后,有很多新功能,很多朋友想要下载并安装,该怎么操作呢?下面我们就来看看详细安装指南... linux Mint 是一款基于 Ubuntu 的流行发行版,凭借其现代、精致、易于使用的特性,深受小伙伴们所喜爱。对

什么是 Linux Mint? 适合初学者体验的桌面操作系统

《什么是LinuxMint?适合初学者体验的桌面操作系统》今天带你全面了解LinuxMint,包括它的历史、功能、版本以及独特亮点,话不多说,马上开始吧... linux Mint 是一款基于 Ubuntu 和 Debian 的知名发行版,它的用户体验非常友好,深受广大 Linux 爱好者和日常用户的青睐,

Linux(Centos7)安装Mysql/Redis/MinIO方式

《Linux(Centos7)安装Mysql/Redis/MinIO方式》文章总结:介绍了如何安装MySQL和Redis,以及如何配置它们为开机自启,还详细讲解了如何安装MinIO,包括配置Syste... 目录安装mysql安装Redis安装MinIO总结安装Mysql安装Redis搜索Red

Linux中Curl参数详解实践应用

《Linux中Curl参数详解实践应用》在现代网络开发和运维工作中,curl命令是一个不可或缺的工具,它是一个利用URL语法在命令行下工作的文件传输工具,支持多种协议,如HTTP、HTTPS、FTP等... 目录引言一、基础请求参数1. -X 或 --request2. -d 或 --data3. -H 或

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后