[Linux] miniaplicación de la barra de progreso

Este blog deducirá principalmente un subprograma de la barra de progreso que se ejecuta en Linux paso a paso, y utilizará el editor vim y el compilador gcc . Si no está familiarizado con estos dos programas, puede hacer clic en el enlace y aprender de este blog. La barra de progreso applet se muestra de la siguiente manera:
inserte la descripción de la imagen aquí

a.\r && \n

Hay muchos caracteres en el lenguaje C, pero macroscópicamente se pueden dividir en dos tipos: caracteres visibles y caracteres de control.

Caracteres visualizables: A, a, B, c... y otros caracteres

Caracteres de control: \n (retorno de carro), \t (tabulador horizontal), \r (avance de línea), etc.

\rAquí necesitamos usar y \ndos caracteres bajo el sistema Linux

Generalmente, cuando usamos el lenguaje C \npara cambiar la línea, o usamos la tecla Enter de la computadora para cambiar la línea, la cambiamos directamente a la posición más a la izquierda de la siguiente línea

int main()
{
    
    
	printf("Hello\nWorld!");

	return 0;
}

inserte la descripción de la imagen aquí

Pero, de hecho, estas son dos acciones, solo en la categoría de idioma. El lenguaje C usa \nlas dos acciones de cambiar a la siguiente línea y regresar a la actual más a la izquierda .

Al igual que nuestro teclado antiguo anterior, la tecla Intro es diferente de la tecla Intro actual, lo que indica que la tecla es la suma de dos acciones.

inserte la descripción de la imagen aquí
Entonces, la nueva línea a la que generalmente nos referimos se compone de estas dos acciones.

Después de comprender el conocimiento anterior, echemos un vistazo al \rsignificado \nde y

\r: retorno de carro (regresar al extremo izquierdo de la línea actual)

\n: Nueva línea (cambiar a la siguiente línea)

inserte la descripción de la imagen aquí
Cuando usamos el lenguaje C \npara el salto de línea, a nivel de lenguaje, se realizan por defecto dos acciones de salto de línea + retorno de carro .

2. El concepto de búfer de línea

pregunta:

Primero observemos la diferencia entre las siguientes dos piezas de código después de ejecutar bajo Linux

  • El archivo ejecutable de las dos piezas de código se llamará MyTest y se ejecutará para mostrar

  • Las funciones se usarán en el código sleep, puede usar el comando man para encontrarlo en el manual No. 3 ( comandos comunes de Linux )

    man 3 sleep
    

    inserte la descripción de la imagen aquí

    • Función: Pausa en el código actual, en segundos.

código 1

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\n");//使用换行符'\n'
   sleep(3);//暂停3秒后继续运行
   return 0;
}

inserte la descripción de la imagen aquí
codigo 2

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\r");//使用回车符'\r'
   sleep(3);//暂停3秒后继续运行
   return 0;
}

inserte la descripción de la imagen aquí

De acuerdo con nuestra lógica normal, ambas piezas de código deberían imprimir algo, pero el código 2 solo ejecuta dormir y no se imprime nada, ¿por qué? ¿Tiene algo \rque \nver?

Este problema involucra el concepto del área de caché (vamos a entender brevemente aquí, el contenido restante del búfer estará en un blog posterior)

respuesta:

Echemos un vistazo al siguiente código y sus resultados de ejecución:

codigo 3

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world");
   sleep(3);//暂停3秒后继续运行
   return 0;
}

inserte la descripción de la imagen aquí

Podemos ver los resultados anteriores, parece que esta vez la función de suspensión se ejecuta primero, después de ejecutar printf y después de la cadena de salida, se emite la línea de comando.

  • El código en lenguaje C ejecuta una estructura secuencial , la cual debe ejecutarse en secuencia y lógica de código, por lo que primero se debe ejecutar printf, y luego dormir.

  • Printf se ejecuta, y debe haber un lugar para almacenar cadenas temporalmente, y este lugar es el área de búfer .

  • Cuando se ejecuta el código, el área del búfer se actualiza y la cadena se imprime en la pantalla. En este momento , la posición del cursor (cursor verde) está detrás de la cadena.

  • En Linux, cada vez que los datos se imprimen en el monitor, comienzan desde la posición del cursor, es decir, el cursor coincide con el monitor, donde está el cursor, la impresión comienza allí.

  • Entonces, la línea de comando se imprimirá directamente después de la cadena. ( El código 1 tiene un salto de línea y el cursor está en una nueva línea)

  • Los diferentes búferes de plataforma tienen diferentes expresiones. En Linux, el búfer tiene su propia estrategia de actualización (muchas)

    Lo que estamos viendo ahora es el caché de línea , que actualizará el área del caché en seis situaciones (solo se presentan tres, y el resto es irrelevante para este artículo)

    1. Se encuentra un carácter de nueva línea, como: \n. ( El código 1 primero ve la cadena y luego duerme)
    2. cuando termina el programa. ( en el caso del código tres )
    3. actualización activa

Del contenido anterior, podemos analizar las razones de la ejecución fallida del código 2 :

Después de ejecutar la función printf, el búfer no se actualiza y los datos se guardan en el búfer.Después de que se ejecuta la suspensión, la cadena se imprime en la pantalla, pero en el contenido anterior lo especificamos \rcomo un retorno de carro, y el cursor regresó al final de la línea izquierda, luego la línea de comando se imprime al comienzo del cursor, sobrescribiendo el contenido de la cadena. Ya no podemos ver nada.

Entonces, ¿hay alguna manera de arreglar esto? Respuesta: No puedo pensar en eso, siempre que lo \rcoloquemos al final de la cadena, la línea de comando eventualmente sobrescribirá la cadena. Incluso si usamos otros caracteres de control para mostrar el resultado, el resultado es diferente de lo que queremos después de todo.

Aquí podemos usar el tercer método de actualizar el caché descrito anteriormente para verificar si nuestra respuesta es correcta y ver la cadena aparecer y desaparecer en la pantalla.

Detección:

Si queremos actualizar activamente el búfer, necesitamos usar fflushfunciones.También podemos usar el comando man para encontrarlo en el manual No. 3. Comandos comunes de Linux

man 3 fflush

inserte la descripción de la imagen aquí

El código de prueba es el siguiente:

#include<stdio.h>
#include<unistd.h>

int main()
{
    
    
   printf("hello world\r");//使用回车符'\r'
   fflush(stdout);//自动刷新缓存区
   sleep(3);//暂停3秒后继续运行
   return 0;
}

inserte la descripción de la imagen aquí

Podemos ver en los resultados que este es el caso, su cursor se mueve hacia el extremo izquierdo y se sobrescribe cuando se imprime la línea de comando, y no podemos ver el resultado en el Código 2 .

expandir

Todo lo impreso en la pantalla es un carácter.

printf("%d",123);
//打印的123,分别为'1'、'2'、'3'

3. Barra de progreso

Visualización de resultados:

inserte la descripción de la imagen aquí
Podemos usar el conocimiento del búfer anterior para implementar un programa tan pequeño en Linux usando lenguaje C

Simplemente podemos dividir un programa tan pequeño en cuatro partes como se muestra en la siguiente figura:

inserte la descripción de la imagen aquí

1. Barra dinámica de progreso

El gráfico del crecimiento de la barra de progreso lo puse en =, y empiezo con el >símbolo

La configuración de la barra de progreso es de 0% a 100% (0% no tiene progreso), necesitamos 100 piezas de tamaño =, y una más >, y agregamos un terminador al final \0, se almacenan un total de 102 bytes, que es el carácter para almacenar la barra de progreso El tamaño de la matriz de tipo es 102.

Nota: Después de crear la matriz, debe continuar inicializándola para que tenga 102 bytes, de modo que pueda \0detenerse con precisión cada vez que alcance la posición actualizada.

Queremos que se actualice cada 1% de la carga. Necesitamos poner la matriz impresa en el bucle y \rcolocarla detrás de la cadena que se va a imprimir. Úselo fflush(stdout)para actualizar automáticamente el área del búfer. Use usleep(unidad de sueño segundos, unidad de sueño us Sutil, puedes probarlo tú mismo para ver cuál es más adecuado) Pausa cada ciclo y continúa, para que puedas mostrar la forma de la barra de progreso subiendo.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

2. Porcentaje de progreso

Imprimimos la barra de progreso en el bucle, siempre que se imprima el número de bucles al imprimir. Nota: el signo de porcentaje significa que %%no se puede usar \%, y se emitirá una alarma. Si la compilación en la primera plataforma falla, se será mostrado.

Modifique el código anterior de la siguiente manera

printf("[%-100s][%d%%]\r",bar,i);

3. Pequeñas decoraciones

Al final de la barra de progreso, agregamos un cursor giratorio para que se vea más vívido,

Aquí | / - \se usan cuatro símbolos para representar el cursor y se almacenan en una matriz. Nota: \ representa un carácter de cambio, y dos \ se usan para representar uno

Girar en el sentido de las agujas del reloj: "|/-\"

Girar en sentido contrario a las agujas del reloj: "|\-/"

Aquí se utiliza el sentido de las agujas del reloj, y el código modificado completo es el siguiente:

  #include<stdio.h>    
  #include<unistd.h>    
  #include<string.h>    
      
  #define N 101    
  #define STYLE '='    
      
  int main()    
  {
    
        
    char bar[N];    
    memset(bar,'\0',sizeof(bar));    
    char lable[4] = "|/-\\";    
    int i=0;    
    while(i<=100)    
    {
    
        
      printf("[%-100s][%d%%][%c]\r",bar,i,lable[i%4]);                                                                                      
      fflush(stdout);    
      usleep(100000);    
      bar[i++] = STYLE;    
      if(i!=100) bar[i] = '>';    
    }    
    printf("\n");    
    return 0;    
  }   

inserte la descripción de la imagen aquí

4. color

Hay muchas formas de cambiar el color de la barra de progreso que mostramos, aquí solo muestro una, los interesados ​​pueden buscarla por sí mismos.

//格式
printf("\e[31m字符串\e[0m");

//31:前景色
//\e[31 :开头
//\e[0m :终止,使改变的颜色只在字符串内

color de primer plano (color de fuente)

personaje color
30 negro
31 rojo
32 verde
33 amarillo
34 azul
35 Púrpura
36 verde oscuro
37 Blanco

Con este conocimiento, podemos cambiar el color de la barra de progreso, volviéndola roja, el código es el siguiente:

#include<stdio.h>
#include<unistd.h>
#include<string.h>

#define N 101
#define STYLE '='

int main()
{
    
    
  char bar[N];
  memset(bar,'\0',sizeof(bar));
  const char* lable = "|/-\\";
  int i=0;
  while(i<=100)
  {
    
    
    printf("[\e[31m%-100s\e[0m][%d%%][%c]\r",bar,i,lable[i%4]);                                                               
    fflush(stdout);                                                   
    usleep(100000);                                                   
    bar[i++] = STYLE;
    if(i!=100) bar[i] = '>';
  }                         
  printf("\n");             
  return 0;    
}  

inserte la descripción de la imagen aquí
El color y la forma de la barra de progreso no son los únicos. Si está interesado, puede buscar más contenido y crear una barra de progreso especial usted mismo.

Supongo que te gusta

Origin blog.csdn.net/m0_52094687/article/details/128720874
Recomendado
Clasificación