Em C, como devo ler um arquivo de texto e imprimir todas as strings


103

Eu tenho um arquivo de texto chamado test.txt

Quero escrever um programa C que possa ler este arquivo e imprimir o conteúdo no console (suponha que o arquivo contenha apenas texto ASCII).

Não sei como obter o tamanho da minha variável de string. Como isso:

O tamanho 999não funciona porque a string retornada por fscanfpode ser maior do que isso. Como posso resolver isso?

Respostas:


142

A maneira mais simples é ler um caractere e imprimi-lo logo após a leitura:

cestá intacima, pois EOFé um número negativo, e um plano charpode estar unsigned.

Se quiser ler o arquivo em partes, mas sem alocação de memória dinâmica, você pode fazer:

O segundo método acima é essencialmente como você lerá um arquivo com uma matriz alocada dinamicamente:

Seu método fscanf()com %so formato perde informações sobre os espaços em branco no arquivo, portanto, não é exatamente copiar um arquivo para stdout.


É possível ler os dados do arquivo sem abrir esse arquivo em c / c ++ ??
Sagar Patel

e se o arquivo de texto contiver valores inteiros separados por vírgula? do que qual seria o código, você pode editar sua resposta com isso também nele.
Mohsin de

A descrição acima funciona para qualquer tipo de arquivo de texto. Se você quiser analisar os números de um arquivo CSV, esse é um problema diferente.
Alok Singhal

1
@overexchange A questão não fala sobre linhas - é sobre ler um arquivo e copiar seu conteúdo para stdout.
Alok Singhal

1
@shjeff Um arquivo não pode conter o caractere EOF. Observe que cé int e C garantirá que EOFnão seja igual a nenhum caractere válido.
Alok Singhal

62

Há muitas respostas boas aqui sobre como lê-lo em partes, só vou mostrar um pequeno truque que lê todo o conteúdo de uma vez em um buffer e o imprime.

Não estou dizendo que é melhor. Não é, e como Ricardo às vezes pode ser ruim, mas acho que é uma boa solução para os casos simples.

Eu polvilhei com comentários porque há muita coisa acontecendo.

Deixe-me saber se é útil ou você pode aprender algo com ele :)


2
Não deveria ser lido em buffer[string_size] = '\0';vez de string_size+1? Afaik a string real vai de 0para string_size-1e o \0caractere precisa estar em string_size, certo?
aepsil0n

4
Usar ftelle fseekencontrar o tamanho de um arquivo não é seguro: securecoding.cert.org/confluence/display/seccode/…
Joakim

1
Este código contém um vazamento de memória, você nunca fecha o arquivo. Falta umfclose(handle)
Joakim de

1
Há um erro de digitação onde você chama fclose (handle), deveria ser fclose (handler)
Eduardo Cobuci

3
Você pode usar em calloc(2)vez de malloc(1)ignorar a necessidade de definir o terminador nulo.

15

Em vez disso, apenas imprima diretamente os caracteres no console porque o arquivo de texto pode ser muito grande e você pode precisar de muita memória.


6

Use "read ()" em vez de fscanf:

DESCRIÇÃO

A função read () deve tentar ler nbytebytes do arquivo associado com o descritor de arquivo aberto,, fildesno buffer apontado por buf.

Aqui está um exemplo:

http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html

Parte desse exemplo:


Uma abordagem alternativa é usar getc/ putcler / escrever 1 caractere por vez. Muito menos eficiente. Um bom exemplo: http://www.eskimo.com/~scs/cclass/notes/sx13.html


readpermitirá que você leia um certo número de caracteres. Leia o suficiente para encher o buffer e, em seguida, despeje-o na tela, limpe-o e repita até chegar ao final do arquivo.
bta

1

Duas abordagens vêm à mente.

Primeiro, não use scanf. Use o fgets()que recebe um parâmetro para especificar o tamanho do buffer e que deixa quaisquer caracteres de nova linha intactos. Um loop simples sobre o arquivo que imprime o conteúdo do buffer deve naturalmente copiar o arquivo intacto.

Em segundo lugar, use fread()ou o idioma C comum com fgetc(). Eles processariam o arquivo em pedaços de tamanho fixo ou um único caractere por vez.

Se você deve processar o arquivo em strings delimitadas por espaços em branco, use fgetsou freadpara ler o arquivo e algo como strtokdividir o buffer em espaços em branco. Não se esqueça de lidar com a transição de um buffer para o próximo, uma vez que suas strings de destino provavelmente ultrapassarão o limite do buffer.

Se houver um requisito externo a ser usado scanfpara fazer a leitura, limite o comprimento da string que ela pode ler com um campo de precisão no especificador de formato. No seu caso com um buffer de 999 bytes, diga scanf("%998s", str);qual irá gravar no máximo 998 caracteres no buffer, deixando espaço para o terminador nul. Se strings únicas maiores que seu buffer forem permitidas, você terá que processá-las em duas partes. Caso contrário, você terá a oportunidade de informar ao usuário sobre um erro educadamente, sem criar uma brecha de segurança de estouro de buffer.

Independentemente disso, sempre valide os valores de retorno e pense em como lidar com entradas incorretas, maliciosas ou apenas malformadas.


1

Você pode usar fgetse limitar o tamanho da string de leitura.

Você pode alterar o whileem seu código para:


0

Você poderia ler o arquivo inteiro com alocação de memória dinâmica, mas não é uma boa ideia porque se o arquivo for muito grande, você pode ter problemas de memória.

Portanto, é melhor ler partes curtas do arquivo e imprimi-lo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.