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?

Richard
fonte

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.

Alok Singhal
fonte
É 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 :)

Ifzawacki
fonte
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.

Sagar Shah
fonte
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

DVK
fonte
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.

RBerteig
fonte
1

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

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

Edu
fonte
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.

Rígon
fonte