【Linux】Linux下实现一个简单的进度条程序

来源:互联网 发布:yum 安装lnmp 编辑:程序博客网 时间:2024/05/04 10:04

       相信大家都下载过东西,那么大家肯定都见过那该死的进度条,每次见到它缓慢的增长都想原地爆炸,那大家有没有想过进度条是怎样实现的?通过以下的分析,会发现进度条的实现其实很简单。

      

而在实现进度条之前,我们先引入缓冲区的概念:

标准I/O库的缓冲主要分为3种:全缓冲、行缓冲和不缓冲

全缓冲:全缓冲就是当输入或输出时,当缓冲区被填满了之后,才会进行实际的I/O操作。

行缓冲:当在输入或输出中遇到换行符时,才进行实际I/O操作。linux下标准输出默认是行缓冲。

无缓冲:标准I/O库不进行任何字符缓冲,任何读写都是即时可见的。linux下标准错误输出默认是不缓冲。


这里就不做详细介绍了,有兴趣的可以看一下这篇博主的文章http://blog.csdn.net/imxiangzi/article/details/45917039


缓冲区的作用:

系统调用

        系统调用是内核提供给上层程序的接口,能够实现内核和上层之间的交互,系统调用在内核中的实现是软中断的方式,通过相应的中断服务例程来实现,而标准库函数是在系统调用的基础之上封装的应用程序,完全运行在用户态,在必要的时候调用系统调用。编写应用程序可以直接使用系统调用也可以使用库函数,那为什么还要有库函数呢。以printf为例,在printf的实现中,在调用write之前加入了IO缓冲区,这是 一个用户空间的缓冲,首先要说明一点,系统调用是软中断,频繁调用,需要内核频繁陷入内核态,这样的效率不是很高,而printf实际是向用户空间的IO 缓冲写,在满足条件的情况下才会调用write系统调用,这样也就提高了内核的效率。

行缓冲

printf是一个行缓冲函数,先写到缓冲区,满足条件后,才将缓冲区刷到对应文件中,刷缓冲区的条件如下:

        1.缓冲区填满

        2.写入的字符中有‘\n’ '\r'

        3.调用fflush手动刷新缓冲区

        4.调用scanf要从缓冲区中读取数据时,也会将缓冲区内的数据刷新

        5.当我们执行printf的进程或者程序结束的时候会主动调用flush来刷新缓冲区,所以程序结束,系统会强制刷新缓冲区


如下:


 如上例子,在字符串"hello world"的后面加上'\n'和不加输出结果的现象是不同的,通过我们刚才对于缓冲区的了解,这个问题就好理解了。第一个因为在输出字符串后添加了“\n”一个行结束标志,缓冲区得到字符“\n”,就会刷新缓冲区的内容到屏幕,然后才执行sleep休眠该进程,最后结束程序。而第二个没有添加“\n”,缓冲区并没有得到“ \n”,就会先把字符串存入到缓冲区中,当该进程休眠1s后,该进程要结束了,此时缓冲区得到结束标志,就会强制刷新缓冲区的内容到屏幕上。


在了解了以上的知识后,我们回到进度条的问题上。


首先要知道进度条的特点:

          1、进度条存在一个区间,不断加载数据,直到区间加载满了。

          2、会显示进度,从0%~100%。

          3、在下载的时候,为使用户区分当前下载是否卡住了,会出现一个旋转的小圈,表示正加载数据。


实现方法


       1、首先我们需要将‘[ ]’固定在进度条的左右两边,中间预留下空间,进度条由0%~100%的状态( 101 个状态),,在字符数组中输出一串字符时,最后以“\0”结束的,故需要一个大小为102的数组,加载成功的数据条长度由“ # ”填充。

      2.我们通过一个数组,每加载成功一次,数组会多出现一个' #'标示。由于进度条是在一行内进行的,故我们需要回车,不需要换行,通过“\r”实现。再次熟悉一下' \n ' 和 ' \r '的区别:       

      \r : return 到当前行的最开始位置。

      \n: newline 向下移动一行,但不移动左右。

      Linux中\n表示回车+换行;

      Windows中\r\n表示回车+换行。


       3、定义一个rate标识进度条的进度,每进行一次加一,直到100时停止。

       4、在进行回车前,需要进行刷新。

       5、在加载进度时,为了不让其一下子输出完,通过sleep()或usleep()控制睡眠时间,sleep以秒为单位,usleep以微秒为单位,linux下sleep包含在头文件#include<unistd.h>中。

       6、对于加载中旋转的小圈通过“| / - \\”逆时针进行。注意:这里出现的两次\\ ,并不是将 \ 打印了两次,而是对 \ 进行转义。


进度条程序


执行结果:


这样一个简单的进度条就实现了,由于我也是初次了解,若有什么问题,请一定要提出。




0 0
原创粉丝点击