[Linux] miniaplicativo da barra de progresso

Este blog deduzirá principalmente um miniaplicativo de barra de progresso em execução no Linux passo a passo e usará o editor vim e o compilador gcc . Se você não estiver familiarizado com esses dois softwares, clique no link e aprenda com este blog. A barra de progresso applet é exibido da seguinte forma:
insira a descrição da imagem aqui

a.\r && \n

Existem muitos caracteres na linguagem C, mas eles podem ser divididos macroscopicamente em dois tipos: caracteres visíveis e caracteres de controle

Caracteres exibíveis: A, a, B, c... e outros caracteres

Caracteres de controle: \n (retorno de carro), \t (tabulação horizontal), \r (alimentação de linha), etc.

\rAqui precisamos usar e \ndois caracteres no sistema Linux

Geralmente, quando usamos a linguagem C \npara alterar a linha ou usamos a tecla Enter do computador para alterar a linha, mudamos diretamente para a posição mais à esquerda da próxima linha

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

	return 0;
}

insira a descrição da imagem aqui

Mas, na verdade, essas são duas ações, apenas na categoria de linguagem. A linguagem C usa \nas duas ações de mudar para a próxima linha e retornar para a atual mais à esquerda .

Como nosso teclado antiquado anterior, a tecla Enter é diferente da tecla Enter atual, indicando que a tecla é a soma de duas ações.

insira a descrição da imagem aqui
Portanto, a nova linha a que geralmente nos referimos é composta por essas duas ações.

Depois de entender o conhecimento acima, vamos dar uma olhada no \rsignificado \ne

\r: retorno de carro (retorna ao extremo esquerdo da linha atual)

\n: Nova linha (mude para a próxima linha)

insira a descrição da imagem aqui
Quando usamos a linguagem C \npara quebra de linha, no nível da linguagem, duas ações de quebra de linha + retorno de carro são executadas por padrão.

2. O conceito de buffer de linha

pergunta:

Vamos primeiro observar a diferença entre os dois trechos de código a seguir após a execução no Linux

  • O arquivo executável das duas partes do código será nomeado MyTest e executado para exibir

  • As funções serão usadas no código sleep, você pode usar o comando man para encontrá-lo no manual nº 3 ( comandos comuns do Linux )

    man 3 sleep
    

    insira a descrição da imagem aqui

    • Função: Pausa no código atual, em segundos.

código 1

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

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

insira a descrição da imagem aqui
código 2

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

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

insira a descrição da imagem aqui

De acordo com nossa lógica normal, os dois trechos de código devem imprimir algo, mas o código 2 apenas executa o modo de suspensão e nada é impresso, por quê? Tem algo \ra \nver?

Este problema envolve o conceito da área de cache (vamos entender brevemente aqui, o restante do conteúdo do buffer ficará em um blog posterior)

responder:

Vamos dar uma olhada no código a seguir e seus resultados em execução:

código 3

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

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

insira a descrição da imagem aqui

Podemos ver os resultados acima, parece que desta vez a função sleep é executada primeiro, após a execução do printf e após a string de saída, a linha de comando é gerada.

  • O código em linguagem C executa uma estrutura sequencial , que deve ser executada em sequência e lógica de código, portanto printf deve ser executado primeiro e depois sleep.

  • Printf é executado e precisa haver um local para armazenar strings temporariamente, e esse local é a área de buffer .

  • Quando o código é executado, a área do buffer é atualizada e a string é impressa na tela. Neste momento , a posição do cursor (cursor verde) está atrás da string.

  • No Linux, toda vez que os dados são impressos no monitor, eles partem da posição do cursor, ou seja, o cursor coincide com o monitor, onde está o cursor, a impressão começa ali.

  • Portanto, a linha de comando será impressa diretamente após a string. ( O código 1 tem uma quebra de linha e o cursor está em uma nova linha)

  • Buffers de plataformas diferentes têm expressões diferentes. No Linux, o buffer tem sua própria estratégia de atualização (muitas)

    O que estamos vendo agora é o cache de linha , que atualizará a área de cache em seis situações (apenas três são introduzidas e o restante é irrelevante para este artigo)

    1. Um caractere de nova linha é encontrado, como: \n. ( O código 1 primeiro vê a string e depois dorme)
    2. quando o programa termina. ( no caso do código três )
    3. atualização ativa

A partir do conteúdo acima, podemos analisar os motivos da execução malsucedida do código 2 :

Depois que a função printf é executada, o buffer não é atualizado e os dados são salvos no buffer. Depois que o sleep é executado, a string é impressa na tela, mas no conteúdo anterior nós \ra especificamos como um retorno de carro e o cursor voltou para o final da linha à esquerda, então a linha de comando é impressa no início do cursor, sobrescrevendo o conteúdo da string. Não podemos ver mais nada.

Então, há uma maneira de consertar isso? Resposta: Não consigo pensar nisso, desde que o \rcoloquemos no final da string, a string será substituída pela linha de comando. Mesmo se usarmos outros caracteres de controle para exibir o resultado, o resultado é diferente do que queremos afinal.

Aqui podemos usar o terceiro método de atualização do cache descrito acima para verificar se nossa resposta está correta e ver a string aparecer e desaparecer na tela.

Detecção:

Se quisermos atualizar ativamente o buffer, precisamos usar fflushfunções.Também podemos usar o comando man para encontrá-lo no manual nº 3. Comandos comuns do Linux

man 3 fflush

insira a descrição da imagem aqui

O código de teste é o seguinte:

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

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

insira a descrição da imagem aqui

Podemos ver pelos resultados que este é o caso, seu cursor é movido para a extrema esquerda e é substituído quando a linha de comando é impressa, e não podemos ver o resultado no Code 2 .

expandir

Tudo impresso no visor é um caractere

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

3. Barra de progresso

Exibição de resultados:

insira a descrição da imagem aqui
Podemos usar o conhecimento do buffer acima para implementar um programa tão pequeno no Linux usando a linguagem C

Podemos simplesmente dividir um programa tão pequeno em quatro partes, conforme mostrado na figura abaixo:

insira a descrição da imagem aqui

1. Barra dinâmica de progresso

O gráfico do crescimento da barra de progresso eu defini como =, e começo com o >símbolo

A configuração da barra de progresso é de 0% a 100% (0% não tem progresso), precisamos de 100 pedaços de tamanho =e mais um >, e adicionar um terminador no final \0, um total de 102 bytes são armazenados, o que é o caractere para armazenar a barra de progresso O tamanho da matriz do tipo é 102.

Nota: Depois de criar o array, você precisa continuar a inicializá-lo para torná-lo 102 bytes, para que ele \0pare com precisão toda vez que atingir a posição atualizada.

Queremos que seja atualizado a cada 1% da carga. Precisamos colocar o array impresso no loop e \rcolocá-lo atrás da string a ser impressa. Use fflush(stdout)-o para atualizar automaticamente a área do buffer. Use usleep(sleep unit segundos, usleep unit Sutil, você mesmo pode tentar ver qual é o mais adequado) Pause cada ciclo e continue, para que você possa mostrar a forma da barra de progresso subindo.

insira a descrição da imagem aqui
insira a descrição da imagem aqui

2. Porcentagem de progresso

Imprimimos a barra de progresso no loop, desde que o número de loops seja impresso ao imprimir. Observação: o sinal de porcentagem significa que %%não pode ser usado \%e será emitido um alarme. Se a compilação na primeira plataforma falhar, será será mostrado.

Modifique o código acima da seguinte maneira

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

3. Pequenas decorações

No final da barra de progresso, adicionamos um cursor giratório para torná-la mais vívida,

Aqui | / - \quatro símbolos são usados ​​para representar o cursor e armazenados em uma matriz. Observação: \ representa um caractere de deslocamento e dois \ são usados ​​para representar um

Girar no sentido horário: "|/-\"

Girar no sentido anti-horário: "|\-/"

Sentido horário é usado aqui, e o código modificado completo é o seguinte:

  #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;    
  }   

insira a descrição da imagem aqui

4. Cor

Existem várias maneiras de alterar a cor da barra de progresso que exibimos. Aqui, mostro apenas uma. Os interessados ​​podem pesquisar por conta própria.

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

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

cor de primeiro plano (cor da fonte)

personagem cor
30 Preto
31 vermelho
32 verde
33 amarelo
34 azul
35 Roxa
36 verde escuro
37 Branco

Com esse conhecimento, podemos mudar a cor da barra de progresso, tornando-a vermelha, o código é o seguinte:

#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;    
}  

insira a descrição da imagem aqui
A cor e o formato da barra de progresso não são os únicos. Se você estiver interessado, pode pesquisar mais conteúdo e criar você mesmo uma barra de progresso especial.

Acho que você gosta

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