【linux】进度条

server/2024/9/29 21:12:48/

Alt

🔥个人主页Quitecoder

🔥专栏linux笔记仓

Alt

目录

    • 01.屏幕缓冲区
      • 换行(LF, `\n`)和回车(CR, `\r`)
      • 换行回车在屏幕缓冲区中的作用
        • 代码块1:
        • 代码块2:
    • 02.进度条
      • 优化版本

01.屏幕缓冲区

屏幕缓冲区是指在输出设备(如终端或控制台)之前,数据被存储的内存区域。应用程序将输出数据写入这个缓冲区,然后系统统一将缓冲区的内容刷新到屏幕上。缓冲区的使用提高了I/O操作的效率,因为它允许数据批量刷新,而不是每次输出都进行一次I/O操作。

缓冲区刷新模式

缓冲区的刷新模式决定了什么时候会将缓冲区内容刷新到终端屏幕上。主要有以下几种模式:

  1. 全缓冲模式(Fully Buffered)

    • 数据只有在缓冲区满时才会被刷新到屏幕上。通常用于文件I/O。
  2. 行缓冲模式(Line Buffered)

    • 当遇到换行字符(LF, \n)时,缓冲区内容会被刷新到屏幕上。常见于终端I/O
    • 一些标准输出流(如stdout)在连接到终端时默认使用行缓冲模式。
  3. 无缓冲模式(Unbuffered)

    • 数据每次写入缓冲区后立即被刷新到屏幕上。适用于需要实时输出的场景,如错误输出流(如stderr)通常是无缓冲的。

换行(LF, \n)和回车(CR, \r

在屏幕缓冲区的刷新以及终端输出中,换行字符和回车字符有着重要的作用:

  1. 换行(Line Feed, \n

    • 功能:将光标移到下一行。
    • 在行缓冲模式下
      • 当输出流遇到换行字符时,缓冲区的内容会被立即刷新到屏幕上,从而实现行缓冲的机制
      • 在许多现代终端和编程环境中,输出一个换行字符通常意味着会将当前行的数据刷新到屏幕
  2. 回车(Carriage Return, \r

    • 功能将光标移动到当前行的起始位置(即行首),但不移动到下一行
    • 用途
      • 常用于覆盖同一行内容,如进度条或动态日志输出。输出回车字符后,下一次的输出会从行首开始,覆盖当前行的内容

换行回车在屏幕缓冲区中的作用

  • 行缓冲模式换行字符(\n)会触发缓冲区刷新,将内容显示到屏幕上。

  • 回车字符(\r不触发缓冲区刷新,而是移动光标,通常与手动刷新缓冲区结合使用,以实现动态行更新。

  • 缓冲区刷新模式(全缓冲、行缓冲和无缓冲)控制了何时将数据从缓冲区刷新到屏幕。

  • 换行字符(\n)在行缓冲模式下起到触发缓冲区刷新的作用,同时将光标移到下一行。

  • 回车字符(\r)将光标移动到行首,常用于覆盖当前行的内容,而不触发缓冲区刷新。

  • 综合使用换行和回车字符,可以实现灵活的终端输出效果,特别在实时显示和动态更新场景中非常常见。

从您提供的代码来看,您有两个几乎相同的代码块,但你希望了解的现象可能是与终端缓冲和输出可见性相关的。让我们总结并推测可能的观察现象。

代码块1:
#include <stdio.h>
#include <unistd.h>  // For sleep()int main() {printf("hello Makefile!\n");sleep(3);return 0;
}
代码块2:
#include <stdio.h>
#include <unistd.h>  // For sleep()int main() {printf("hello Makefile!");sleep(3);return 0;
}

终端输出现象

代码块1:

printf("hello Makefile!\n");
  • 输出字符串 “hello Makefile!” 后接换行符 \n
  • 在行缓冲模式下,遇到 \n 立即刷新输出缓冲区内容到终端。
  • 您会立即看到 “hello Makefile!” 和换行,接下来程序会暂停3秒钟,然后退出。

终端显示:

hello Makefile!(暂停3秒钟)

代码块2:

printf("hello Makefile!");
  • 输出字符串 “hello Makefile!”,但没有换行符 \n
  • 在行缓冲模式下,由于没有遇到 \n,缓冲区不立即刷新到终端,除非缓冲区满或者进程结束。
  • 因为接下来代码调用 sleep(3) 而没有刷新缓冲区,所以在大多数情况下,您在终端上可能看不到立即的输出。
  • 直到程序退出或缓冲区被手动刷新,“hello Makefile!” 的内容才会显示。

终端显示:

(暂停3秒钟)
hello Makefile!

如果你希望在没有换行符的情况下立即刷新输出缓冲区,可以在 printf 后调用 fflush(stdout)

修改后的代码块2:

#include <stdio.h>
#include <unistd.h>int main() {printf("hello Makefile!");fflush(stdout);    // 手动刷新标准输出缓冲区sleep(3);return 0;
}

这样做确保 “hello Makefile!” 会立即显示在终端上,不需要等到程序退出或缓冲区满。

终端显示:

hello Makefile!
(暂停3秒钟)
  • 带有换行符 \nprintf 在行缓冲模式下会立即刷新到终端。
  • 没有换行符的 printf 可能不会立即刷新缓冲区,需要手动调用 fflush(stdout)
  • 使用 \nfflush(stdout) 确保输出立即可见,尤其是在待运行一段时间的代码(如 sleep())之后进行输出时。

这些现象主要源于终端缓冲机制的行为,在不同开发和调试环境中(特别是高速输出场景下)理解这些机制尤其有用。

02.进度条

有了上面缓冲区的知识,我们就可以实现一个简易版的进度条

在这里插入图片描述
文件结构如下
在这里插入图片描述

在这里插入图片描述
准备工作完成后,我们下面只需完成进度条的主体代码即可

#include"Processbar.h"
#include<string.h>
#include<unistd.h>#define length 101
#define Style '#' void Procbar()
{char bar[101];memset(bar,'\0',sizeof(bar));int cnt=0;while(cnt<=100){printf("[%-100s][%d%%]\r",bar,cnt);fflush(stdout);bar[cnt++]=Style;usleep(10000);}printf("\n");
}

进度条显示函数 Procbar

  • char bar[length];:声明一个字符数组 bar,长度为 length(101 个字符),用于存储进度条的内容。
  • memset(bar, '\0', sizeof(bar));:将 bar 数组的所有元素初始化为\0表示进度条初始为空
  • int cnt = 0;:初始化一个整型变量 cnt,作为进度百分比,从0开始。
  • while(cnt <= 100):使用 while 循环,将 cnt 从0逐步增到100,模拟从0%到100%的进度条显示。
    • printf("[%-100s][%d%%]\r", bar, cnt);格式化输出进度条。%-100s表示左对齐,宽度为100的字符串,%d%%表示当前的百分比。\r 让光标返回行首
    • fflush(stdout);刷新标准输出,使得进度条及时更新
    • bar[cnt++] = Style;bar 数组的第 cnt 个位置设置为 #,并将 cnt 递增1,表示进度条推进一格
    • usleep(10000);:暂停程序10毫秒,以模拟进度条的动态效果。
  • printf("\n");循环结束后,打印一个换行符,结束进度条的显示

优化版本

在这里插入图片描述
我们设置文件大小和带宽速度,这时候进度条的函数需要进行修改

  1 #include"Processbar.h"2 #include<unistd.h>3 4 void download()5 {6   double filesize=100*1024*1024*1.0;7   double current=0.0;8   double bandwidth=1024*1024*1.0;9   printf("download begin,current: %lf\n",current);10   while(current<=filesize)11   {12     Procbar(filesize,current);13     current+=bandwidth;14     usleep(10000);15   }                                                                                                                   16 17   printf("\ndownload done ,filesize: %lf\n",filesize);18 }19 int main()20 {21  // download();22  // Procbar(100.0,69.0);23    download();24   return 0;25 }
  1 #include"Processbar.h"2 #include<string.h>3 #include<unistd.h>4 5 #define length 1016 #define Style '#' 7 8 void Procbar(double total,double current)9 {10   char bar[101];11 12   memset(bar,'\0',sizeof(bar));13   int cnt=0;14   double rate = (current*100.0)/total;15   int loop_count =(int)rate;16 17   while(cnt<=loop_count)18   {19     bar[cnt++]=Style;20   }                                                                                                                   21    printf("[%-100s][%.1lf%%]\r",bar,rate);22    fflush(stdout);23 }

http://www.ppmy.cn/server/124652.html

相关文章

2024年7天自学网络安全(黑客技术)进阶手册。

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、…

PHP include和require的区别

1. 基本概念 include 和 require 是PHP中用于在当前文件中包含&#xff08;或插入&#xff09;另一个文件内容的两个语句。它们的主要目的是代码复用&#xff0c;通过包含&#xff08;或引用&#xff09;外部文件的方式&#xff0c;使得PHP代码更加模块化和易于管理。然而&…

python中的assert语句

1.什么是assert 程序运行过程中,所有变量的当前值组合构成了“状态“; 每执行一段程序,状态就发生变化;如果程序有逻辑错误的bug,必定在处变量值的组合不符合预期,处于错误状态; 将对变量的预期写为断言,可以定位复杂的逻辑错误。 语法: assert <表达式> [, …

使用Postman工具接口测试

文章目录 一、接口1.1 接口的概念1.2 接口的类型 二、接口测试2.1 概念2.2 原理2.3 特点 三、HTTP协议3.1 http协议简介3.2 URL格式3.3 HTTP请求3.3.1 请求行3.3.2 请求头3.3.3 请求体 3.4 HTTP响应3.4.1 状态行3.4.2 响应头3.4.3 响应体 3.4 传统风格接口3.5 RESTful风格接口 …

python --qt5(webview)/防多开/套壳网页/多次点击激活旧窗口

pyqtwebengine5.12 PyQt55.12class MyWindow(QMainWindow):def __init__(self):super(MyWindow, self).__init__()self.browser QWebEngineView(self) # 如果不写self则新生成一个窗口self.browser.setWindowTitle(技术领域占比分析)self.browser.setWindowIcon(QIcon(LOGO_P…

关于 SQL 的 JOIN 操作

关于 SQL 的 JOIN 操作 在关系型数据库中&#xff0c;数据通常分布在多个表中。为了进行有效的数据检索&#xff0c;我们需要从不同的表中组合数据&#xff0c;这时就需要使用 JOIN 操作。本文将深入探讨 SQL 中不同类型的 JOIN 及其用法&#xff0c;以帮助你在数据库查询中更…

Nginx反向代理配置支持websocket

一、官方文档 WebSocket proxying 为了将客户端和服务器之间的连接从HTTP/1.1转换为WebSocket&#xff0c;使用了HTTP/1.1中可用的协议切换机制&#xff08;RFC 2616: Hypertext Transfer Protocol – HTTP/1.1&#xff09;。 然而&#xff0c;这里有一个微妙之处:由于“升级”…

软件测试之单元测试/系统测试/集成测试详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、单元测试的概念 单元测试是对软件基本组成单元进行的测试&#xff0c;如函数或一个类的方法。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff0…