421 votes

Comment puis-je obtenir la taille d'un fichier en C ?

Comment puis-je connaître la taille d'un fichier que j'ai ouvert avec une application écrite en C ? Je voudrais connaître la taille, car je veux mettre le contenu du fichier chargé dans une chaîne de caractères, que j'alloue à l'aide de malloc() . Il suffit d'écrire malloc(10000*sizeof(char)); est, à mon avis, une mauvaise idée.

42 votes

Notez que sizeof(char) est égal à 1, par définition.

11 votes

Oui, mais le compilateur d'une plate-forme ésotérique peut définir char comme 2 octets - le programme alloue alors plus que nécessaire. On ne peut jamais être trop sûr.

36 votes

@George un "compilateur de plateforme ésotérique" où sizeof(char) != 1 n'est pas un vrai compilateur C. Même si un caractère est de 32 bits, il retournera toujours 1.

578voto

Rob Walker Points 25840

Vous devez chercher jusqu'à la fin du dossier et ensuite demander la position :

fseek(fp, 0L, SEEK_END);
sz = ftell(fp);

Vous pouvez alors chercher à nouveau, par exemple :

fseek(fp, 0L, SEEK_SET);

ou (si l'on veut aller au début)

rewind(fp);

13 votes

@camh - Merci mec. Ce commentaire a permis de résoudre un problème que j'avais avec un algorithme de dimensionnement de fichier. Pour mémoire, on ouvre un fichier en mode binaire en mettant un 'b' à la fin de la chaîne mode de fopen.

4 votes

LOL, ouais c'est ça, Windows a hérité de cette stupide absurdité de mode texte/binaire du DOS. On l'oublie facilement de nos jours. En fait, la norme POSIX stipule même que tout système POSIX doit être capable de gérer le drapeau "b" dans les appels fopen (pour être compatible avec la norme C !), mais d'un autre côté, elle stipule que l'implémentation doit l'ignorer complètement, puisque ce drapeau n'a aucun effet sur les systèmes POSIX (qui ne connaissent pas le mode texte et ouvrent toujours en mode binaire).

66 votes

Yo uh, utilise rewind avant que les gens oublient ce que cela signifie

406voto

Greg Hewgill Points 356191

Utilisation de la bibliothèque standard :

En supposant que votre implémentation supporte significativement SEEK_END :

fseek(f, 0, SEEK_END); // seek to end of file
size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
// proceed with allocating memory and reading the file

Linux/POSIX :

Vous pouvez utiliser stat (si vous connaissez le nom du fichier), ou fstat (si vous avez le descripteur de fichier).

Voici un exemple pour la stat :

#include <sys/stat.h>
struct stat st;
stat(filename, &st);
size = st.st_size;

Win32 :

Vous pouvez utiliser GetFileSize o GetFileSizeEx .

17 votes

Veuillez noter que j'ai omis de vérifier les erreurs dans un souci de clarté.

20 votes

Vous n'avez pas besoin du nom du fichier - vous pouvez utiliser fstat pour cela.

4 votes

Vous devez indiquer l'adresse de la structure. La deuxième ligne devrait être : stat(nom du fichier, &st) ;

119voto

PiedPiper Points 3595

Si vous avez le descripteur de fichier fstat() renvoie une structure stat qui contient la taille du fichier.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// fd = fileno(f); //if you have a stream (e.g. from fopen), not a file descriptor.
struct stat buf;
fstat(fd, &buf);
off_t size = buf.st_size;

3 votes

Ajoutez "fd = fileno(f) ;" si vous avez un flux (par exemple de fopen), pas un descripteur de fichier. Nécessite un contrôle d'erreur.

15 votes

Bien sûr, il faut un contrôle des erreurs, mais cela ne ferait que compliquer l'exemple.

6 votes

C'est à mon avis la meilleure réponse réelle, et je pense que nous avons tous enlevé les roues d'entraînement pour la plupart en C, avons-nous vraiment besoin de la vérification des erreurs et d'autres codes inutiles dans nos exemples, c'est déjà assez mauvais que M$DN le fasse dans les siens, ne suivons pas le mouvement, disons plutôt à la fin "assurez-vous d'ajouter la vérification des erreurs" et finissons-en.

9voto

Pat Morin Points 81

Avez-vous envisagé de ne pas calculer la taille du fichier et de simplement agrandir le tableau si nécessaire ? Voici un exemple (sans vérification des erreurs) :

#define CHUNK 1024

/* Read the contents of a file into a buffer.  Return the size of the file 
 * and set buf to point to a buffer allocated with malloc that contains  
 * the file contents.
 */
int read_file(FILE *fp, char **buf) 
{
  int n, np;
  char *b, *b2;

  n = CHUNK;
  np = n;
  b = malloc(sizeof(char)*n);
  while ((r = fread(b, sizeof(char), CHUNK, fp)) > 0) {
    n += r;
    if (np - n < CHUNK) { 
      np *= 2;                      // buffer is too small, the next read could overflow!
      b2 = malloc(np*sizeof(char));
      memcpy(b2, b, n * sizeof(char));
      free(b);
      b = b2;
    }
  }
  *buf = b;
  return n;
}

Cela a l'avantage de fonctionner même pour les flux pour lesquels il est impossible d'obtenir la taille du fichier (comme stdin).

19 votes

Peut-être que le realloc pourrait être utilisée ici au lieu d'utiliser un pointeur intermédiaire et d'avoir à free() .

0 votes

Cela a le réel inconvénient d'être O(n^2) ... la taille de ce que vous devez copier augmente. OK pour les petits fichiers, TERRIBLE pour les gros. Si vous avez un chunk de 1k et un fichier de 100M, vous finissez par copier (si j'ai bien fait mes calculs) environ 1E17 octets. C'est peut-être un exemple pathologique, mais il démontre pourquoi vous ne devriez pas faire cela.

3 votes

Sauf erreur de ma part, la taille stockée est doublée à chaque fois. Le temps d'exécution est donc O(n) plutôt que O(n^2). C'est la même stratégie d'allocation qui est typiquement utilisée pour std::vector et ses semblables. Quoi qu'il en soit, les réallocations sont toujours moins efficaces que l'interrogation de la taille du fichier et la lecture en une seule fois.

8voto

Ben Combee Points 7193

Si vous êtes sous Linux, envisagez sérieusement d'utiliser simplement l'option g_file_get_contents de la fonction glib. Elle gère tout le code pour charger un fichier, allouer de la mémoire et gérer les erreurs.

40 votes

Si vous êtes sous Linux et veulent avoir une dépendance sur glib, c'est-à-dire.

2 votes

Ce n'est pas un si gros problème, car glib est utilisé par les applications GTK et KDE maintenant. Il est également disponible sur Mac OS X et Windows, mais il est loin d'être aussi standard là-bas.

1 votes

Mais glib n'est-elle pas une bibliothèque c++ ? La question stipulait que C

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