126 votes

En C, comment dois-je lire un fichier texte et imprimer toutes les chaînes de caractères

J'ai un fichier texte nommé test.txt

Je veux écrire un programme C qui peut lire ce fichier et afficher le contenu dans la console (en supposant que le fichier contient uniquement du texte ASCII).

Je ne sais pas comment obtenir la taille de ma variable de chaîne. Comme ceci:

char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
    while (fscanf(file, "%s", str)!=EOF)
        printf("%s",str);
    fclose(file);
}

La taille de 999 ne fonctionne pas car la chaîne retournée par fscanf peut être plus grande que cela. Comment puis-je résoudre cela?

163voto

Alok Singhal Points 33073

La manière la plus simple est de lire un caractère et de l'imprimer juste après la lecture :

int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
    while ((c = getc(file)) != EOF)
        putchar(c);
    fclose(file);
}

c est int ci-dessus, puisque EOF est un nombre négatif, et un simple char peut être unsigned.

Si vous voulez lire le fichier par morceaux, mais sans allocation dynamique de mémoire, vous pouvez faire :

#define CHUNK 1024 /* lire 1024 octets à la fois */
char buf[CHUNK];
FILE *file;
size_t nread;

file = fopen("test.txt", "r");
if (file) {
    while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
        fwrite(buf, 1, nread, stdout);
    if (ferror(file)) {
        /* traiter l'erreur */
    }
    fclose(file);
}

La deuxième méthode ci-dessus est essentiellement comment vous lirez un fichier avec un tableau alloué dynamiquement :

char *buf = malloc(chunk);

if (buf == NULL) {
    /* traiter l'échec de malloc() */
}

/* sinon faites ceci. Notez 'chunk' au lieu de 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
    /* comme ci-dessus */
}

Votre méthode de fscanf() avec %s comme format perd des informations sur les espaces blancs dans le fichier, donc ce n'est pas exactement copier un fichier vers stdout.

76voto

lfzawacki Points 539

Il y a suffisamment de bonnes réponses ici sur la lecture par morceaux, je vais juste vous montrer un petit truc qui lit tout le contenu en une seule fois dans un tampon et l'affiche.

Je ne dis pas que c'est mieux. Ce n'est pas le cas, et comme Ricardo parfois cela peut être mauvais, mais je trouve que c'est une bonne solution pour les cas simples.

Je l'ai parsemé de commentaires car il y a beaucoup de choses qui se passent.

#include <stdio.h>
#include <stdlib.h>

char* ReadFile(char *filename)
{
   char *buffer = NULL;
   int string_size, read_size;
   FILE *handler = fopen(filename, "r");

   if (handler)
   {
       // Chercher le dernier octet du fichier
       fseek(handler, 0, SEEK_END);
       // Décalage du premier au dernier octet, ou en d'autres termes, la taille du fichier
       string_size = ftell(handler);
       // revenir au début du fichier
       rewind(handler);

       // Allouer une chaîne qui peut tout contenir
       buffer = (char*) malloc(sizeof(char) * (string_size + 1) );

       // Le lire en une seule opération
       read_size = fread(buffer, sizeof(char), string_size, handler);

       // fread ne le définit pas donc mettre un \0 à la dernière position
       // et le tampon est maintenant officiellement une chaîne
       buffer[string_size] = '\0';

       if (string_size != read_size)
       {
           // Quelque chose s'est mal passé, jeter la mémoire et définir
           // le tampon sur NULL
           free(buffer);
           buffer = NULL;
       }

       // N'oubliez jamais de fermer le fichier.
       fclose(handler);
    }

    return buffer;
}

int main()
{
    char *string = ReadFile("yourfile.txt");
    if (string)
    {
        puts(string);
        free(string);
    }

    return 0;
}

Dites-moi si c'est utile ou si vous avez pu apprendre quelque chose :)

2 votes

Ne devrait-il pas être lu buffer[string_size] = '\0'; au lieu de string_size+1? À ma connaissance la chaîne réelle va de 0 à string_size-1 et le caractère \0 doit donc être à la position string_size, non ?

0 votes

Vous avez raison, je l'ai corrigé. Cette réponse est là depuis un certain temps et ce problème est passé inaperçu, on adore le C :)

0 votes

Oui, c'est un peu étrange... J'ai dû rencontrer un segfault avant de m'en rendre compte. Le langage C est vraiment trop bas niveau à mon goût.

17voto

Sagar Shah Points 36

Au lieu d'imprimer directement les caractères sur la console car le fichier texte peut être très grand et vous pourriez avoir besoin de beaucoup de mémoire.

#include 
#include 

int main() {

    FILE *f;
    char c;
    f=fopen("test.txt","rt");

    while((c=fgetc(f))!=EOF){
        printf("%c",c);
    }

    fclose(f);
    return 0;
}

9voto

DVK Points 63282

Utilisez "read()" plutôt que fscanf :

ssize_t read(int fildes, void *buf, size_t nbyte);

DESCRIPTION

La fonction read() tentera de lire nbyte octets du fichier associé au descripteur de fichier ouvert, fildes, dans le tampon pointé par buf.

Voici un exemple:

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

Partie fonctionnelle de cet exemple:

f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
    write(1,l,n);

Une approche alternative est d'utiliser getc/putc pour lire/écrire 1 caractère à la fois. Beaucoup moins efficace. Un bon exemple: http://www.eskimo.com/~scs/cclass/notes/sx13.html

3voto

Edu Points 1053

Vous pouvez utiliser fgets et limiter la taille de la chaîne lue.

char *fgets(char *str, int num, FILE *stream);

Vous pouvez changer le while dans votre code pour :

while (fgets(str, 100, file)) /* printf("%s", str) */;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X