HOWTO · C

Ler o arquivo linha por linha usando fscanf em C

Este artigo demonstra como ler o arquivo linha por linha usando fscanf em C

Nesta página

fscanf lê entrada formatada de um fluxo FILE. Um scanset pode coletar caracteres até uma quebra de linha, mas, ao contrário de uma função própria para ler linhas, exige tratamento explícito para linhas em branco e blocos limitados. Para arquivos de texto comuns, fgets costuma ser a opção mais simples; use fscanf quando o formato da entrada exigir conversões.

Leia um arquivo linha por linha com fscanf em C

Este exemplo completo cria um arquivo temporário, grava duas linhas de exemplo e lê o fluxo com um scanset limitado ao buffer de destino de 16 bytes. O programa grava duas linhas de exemplo em um fluxo temporário e as imprime à medida que as lê. As mensagens exibidas nos blocos de código permanecem em inglês.

#include <stdio.h>

int main(void) {
    FILE *file = tmpfile();
    char line[16];

    if (file == NULL) {
        return 1;
    }
    if (fputs("First line.\nSecond line.\n", file) == EOF || ferror(file)) {
        fclose(file);
        return 1;
    }
    if (fflush(file) == EOF || ferror(file)) {
        fclose(file);
        return 1;
    }
    rewind(file);

    for (;;) {
        int result = fscanf(file, "%15[^\n]", line);
        if (result == 1) {
            int ch;
            puts(line);
            ch = fgetc(file);
            if (ch == '\n') {
                continue;
            }
            if (ch == EOF) {
                break;
            }
            ungetc(ch, file);
            while ((ch = fgetc(file)) != '\n' && ch != EOF) {
            }
            if (ch == EOF) {
                break;
            }
            continue;
        }
        if (result == EOF) {
            break;
        }
        if (fgetc(file) == '\n') {
            puts("");
        }
    }

    fclose(file);
    return 0;
}

Uma largura de 15 deixa espaço para o caractere nulo terminador em line. Depois de cada conversão bem-sucedida do scanset, o programa verifica se há uma quebra de linha. Se uma linha ultrapassar o buffer, o restante é descartado antes da leitura da próxima; isso mantém o uso de memória limitado, mas não preserva a linha longa por inteiro. Quando o scanset não encontra nenhum caractere antes de uma quebra de linha, o laço consome essa quebra e imprime uma linha em branco, em vez de tentar novamente sem avançar na entrada. Em código de produção, também convém verificar ferror(file) depois que a leitura termina para distinguir um erro de leitura do fim normal do arquivo.

Leia tokens delimitados por espaços em branco com fscanf

Para analisar tokens, %255s lê um token sem espaços em branco para o buffer char token[256]. A largura evita gravações além dos limites do array, e %s ignora os espaços em branco iniciais e para no próximo caractere desse tipo. O laço deve continuar somente enquanto fscanf(file, "%255s", token) == 1; verificar apenas EOF pode fazer o laço se repetir indefinidamente quando uma conversão falha sem consumir a entrada. Essa abordagem trata espaços, tabulações e quebras de linha como separadores de propósito, portanto não preserva os limites das linhas originais. Para campos numéricos, use especificadores de conversão compatíveis e verifique o número de atribuições bem-sucedidas.

Use fgets para ler linhas de forma confiável

Para textos em que cada registro corresponde a uma linha, geralmente é mais fácil entender fgets(buffer, sizeof buffer, file). A função lê no máximo um caractere a menos que a capacidade do buffer e mantém a quebra de linha quando ela cabe. Verifique o valor retornado antes de usar o buffer. Se o buffer ficar cheio sem conter uma quebra de linha, a linha lógica continua no fluxo; leia blocos adicionais ou descarte o restante, conforme a tarefa. A última linha pode terminar no fim do arquivo sem uma quebra de linha. fgets também lida naturalmente com linhas em branco, pois pode retornar um buffer que contém somente a quebra de linha.

Escolha fscanf quando precisar ler campos formatados ou tokens delimitados por espaços em branco. Escolha fgets quando for importante preservar os limites das linhas e, se necessário, analise a string resultante separadamente. Sempre verifique se fopen teve êxito, confira os resultados das conversões e feche os fluxos após o uso.