web-dev-qa-db-fra.com

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

J'ai un fichier texte nommé test.txt

Je souhaite écrire un programme C capable de lire ce fichier et d’en imprimer le contenu sur la console (en supposant que le fichier ne contienne que le texte ASCII.).

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

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 999 ne fonctionne pas car la chaîne renvoyée par fscanf peut être plus grande que cela. Comment puis-je résoudre ça?

79
Richard

Le moyen le plus simple est de lire un caractère et de l'imprimer juste après avoir lu:

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 qu'un simple char peut être unsigned.

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

#define CHUNK 1024 /* read 1024 bytes at a time */
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)) {
        /* deal with error */
    }
    fclose(file);
}

La deuxième méthode ci-dessus consiste essentiellement à lire un fichier avec un tableau alloué dynamiquement:

char *buf = malloc(chunk);

if (buf == NULL) {
    /* deal with malloc() failure */
}

/* otherwise do this.  Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
    /* as above */
}

Votre méthode de fscanf() avec %s en tant que format perd les informations sur les espaces dans le fichier. Il ne s'agit donc pas de copier un fichier dans stdout.

119
Alok Singhal

Il y a beaucoup de bonnes réponses ici pour le lire en morceaux, je vais juste vous montrer un petit truc qui lit tout le contenu en même temps dans un tampon et l'imprime.

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

Je l'ai saupoudré de commentaires parce qu'il se passe beaucoup de choses.

#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)
   {
       // Seek the last byte of the file
       fseek(handler, 0, SEEK_END);
       // Offset from the first to the last byte, or in other words, filesize
       string_size = ftell(handler);
       // go back to the start of the file
       rewind(handler);

       // Allocate a string that can hold it all
       buffer = (char*) malloc(sizeof(char) * (string_size + 1) );

       // Read it all in one operation
       read_size = fread(buffer, sizeof(char), string_size, handler);

       // fread doesn't set it so put a \0 in the last position
       // and buffer is now officially a string
       buffer[string_size] = '\0';

       if (string_size != read_size)
       {
           // Something went wrong, throw away the memory and set
           // the buffer to NULL
           free(buffer);
           buffer = NULL;
       }

       // Always remember to close the file.
       fclose(handler);
    }

    return buffer;
}

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

    return 0;
}

Faites-moi savoir si c'est utile ou si vous pouviez en apprendre quelque chose :)

54
lfzawacki

Au lieu de cela, imprimez directement les caractères sur la console car le fichier texte est peut-être très volumineux et vous risquez de nécessiter beaucoup de mémoire.

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

int main() {

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

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

    fclose(f);
    return 0;
}
12
Sagar Shah

Utilisez "read ()" à la place de fscanf:

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

LA DESCRIPTION

La fonction read () doit tenter de lire nbyte octets du fichier associé au descripteur de fichier ouvert, fildes, dans la mémoire tampon désignée par buf.

Voici un exemple:

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

Partie de travail de cet exemple:

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

Une autre approche consiste à 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

6
DVK

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

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

Vous pouvez remplacer le while dans votre code par:

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

Deux approches me viennent à l’esprit.

Tout d'abord, n'utilisez pas scanf. Utilisez fgets() qui prend un paramètre pour spécifier la taille de la mémoire tampon et qui laisse les caractères de nouvelle ligne intacts. Une simple boucle sur le fichier qui imprime le contenu de la mémoire tampon devrait naturellement copier le fichier intact.

Deuxièmement, utilisez fread() ou le langage C commun avec fgetc(). Ceux-ci traiteraient le fichier en morceaux de taille fixe ou en un seul caractère à la fois.

Si vous devez traiter le fichier sur des chaînes délimitées par des espaces, utilisez soit fgets ou fread pour lire le fichier, et quelque chose comme strtok pour diviser le tampon à des espaces. N'oubliez pas de gérer la transition d'une mémoire tampon à l'autre, car vos chaînes cible risquent de s'étendre sur la limite de la mémoire tampon.

S'il existe une exigence externe d'utiliser scanf pour effectuer la lecture, limitez la longueur de la chaîne qu'il est possible de lire avec un champ de précision dans le spécificateur de format. Dans votre cas avec un tampon de 999 octets, dites alors scanf("%998s", str); qui écrira au maximum 998 caractères dans le tampon en laissant de la place au terminateur nul. Si des chaînes uniques plus longues que votre mémoire tampon sont autorisées, vous devrez les traiter en deux parties. Si ce n'est pas le cas, vous avez la possibilité de signaler poliment une erreur à l'utilisateur sans créer de faille de sécurité liée au débordement de la mémoire tampon.

Quoi qu'il en soit, validez toujours les valeurs de retour et réfléchissez à la façon de gérer les entrées mauvaises, malveillantes ou simplement mal formées.

1
RBerteig
#include <stdio.h>
#include <stdlib.h>
int main() {

int num;
FILE *fptr; 



if ((fptr = fopen("/root/Desktop/my_pass.txt","r")) == NULL) {       // checks if file exists
    puts("File not exists");
    exit(1);                    // for exit(1) is required #include <stdlib.h> 
} else 

fscanf(fptr,"%d", &num);                

printf("My pass is:  %d\n", num);           
fclose(fptr); 

return 0;
}
1
Odin

Vous pouvez lire le fichier entier avec l'allocation de mémoire dynamique, mais ce n'est pas une bonne idée car si le fichier est trop volumineux, vous pourriez avoir des problèmes de mémoire.

Il est donc préférable de lire de courtes parties du fichier et de l’imprimer.

#include <stdio.h>
#define BLOCK   1000

int main() {
    FILE *f=fopen("teste.txt","r");
    int size;
    char buffer[BLOCK];
    // ...
    while((size=fread(buffer,BLOCK,sizeof(char),f)>0)
            fwrite(buffer,size,sizeof(char),stdout);
    fclose(f);
    // ...
    return 0;
}
0
rigon