168 votes

Comment déterminer la taille d'un fichier en C ?

Comment puis-je connaître la taille d'un fichier, en octets ?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}

0 votes

Vous allez devoir utiliser une fonction de bibliothèque pour récupérer les détails d'un fichier. Comme le C est complètement indépendant de la plate-forme, vous devrez nous dire pour quelle plate-forme/système d'exploitation vous développez !

1 votes

Pourquoi char* file Pourquoi pas ? FILE* file ? -1

0 votes

@user12211554 pour que... juste... strlen ¡!

175voto

Ted Percival Points 3712

Sur les systèmes de type Unix, vous pouvez utiliser les appels système POSIX : stat sur un chemin ou fstat sur un descripteur de fichier déjà ouvert (POSIX page de manuel Linux page de manuel ).
(Obtenir un descripteur de fichier à partir de open(2) ou fileno(FILE*) sur un flux stdio).

Basé sur le code de NilObject :

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

off_t fsize(const char *filename) {
    struct stat st; 

    if (stat(filename, &st) == 0)
        return st.st_size;

    return -1; 
}

Changements :

  • Faire de l'argument du nom de fichier un const char .
  • Corrigé le struct stat qui n'avait pas le nom de la variable.
  • Renvoie à -1 en cas d'erreur, au lieu de 0 ce qui serait ambigu pour un fichier vide. off_t est un type signé, ce qui est donc possible.

Si vous voulez fsize() pour imprimer un message en cas d'erreur, vous pouvez utiliser ceci :

#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

off_t fsize(const char *filename) {
    struct stat st;

    if (stat(filename, &st) == 0)
        return st.st_size;

    fprintf(stderr, "Cannot determine size of %s: %s\n",
            filename, strerror(errno));

    return -1;
}

Sur les systèmes 32 bits, vous devez le compiler avec l'option -D_FILE_OFFSET_BITS=64 sinon off_t ne pourra contenir que des valeurs allant jusqu'à 2 Go. Consultez la section "Utilisation de LFS" de Support des gros fichiers sous Linux pour les détails.

22 votes

C'est spécifique à Linux/Unix - cela vaut la peine de le préciser puisque la question ne spécifiait pas de système d'exploitation.

1 votes

Vous pourriez probablement changer le type de retour en ssize_t et convertir la taille à partir d'un off_t sans problème. Il semblerait plus logique d'utiliser un ssize_t :-) (À ne pas confondre avec size_t qui est non signé et ne peut être utilisé pour indiquer une erreur).

1 votes

Pour un code plus portable, utilisez fseek + ftell comme proposé par Derek.

82voto

Orion Edwards Points 54939

N'utilisez pas int . Les fichiers de plus de 2 gigaoctets sont monnaie courante de nos jours.

N'utilisez pas unsigned int . Les fichiers de plus de 4 gigaoctets sont courants, tout comme certaines saletés un peu moins courantes.

IIRC la bibliothèque standard définit off_t comme un entier 64 bits non signé, ce qui est ce que tout le monde devrait utiliser. Nous pourrons le redéfinir en 128 bits dans quelques années, lorsque nous commencerons à avoir des fichiers de 16 exaoctets.

Si vous êtes sous Windows, vous devriez utiliser GetFileSizeEx - il utilise en fait un entier 64 bits signé, donc ils vont commencer à avoir des problèmes avec des fichiers de 8 exabytes. Stupide Microsoft ! :-)

3 votes

J'ai utilisé des compilateurs où off_t est en 32 bits. Bien sûr, c'est sur des systèmes embarqués où les fichiers de 4GB sont moins courants. Quoi qu'il en soit, POSIX définit également off64_t et les méthodes correspondantes pour ajouter à la confusion.

1 votes

J'aime toujours les réponses qui supposent Windows et ne font rien d'autre que critiquer la question. Pourriez-vous ajouter quelque chose qui soit conforme à POSIX ?

2 votes

@JL2210 la réponse acceptée de Ted Percival montre une solution conforme à Posix, donc je ne vois pas l'intérêt de répéter l'évidence. J'ai (et 70 autres) pensé que l'ajout de la note concernant Windows et la non-utilisation d'entiers 32 bits signés pour représenter les tailles de fichiers était une valeur ajoutée en plus de cela. Au revoir

34voto

Derek Park Points 25025

La solution de Matt devrait fonctionner, sauf qu'il s'agit de C++ au lieu de C, et que le tell initial ne devrait pas être nécessaire.

unsigned long fsize(char* file)
{
    FILE * f = fopen(file, "r");
    fseek(f, 0, SEEK_END);
    unsigned long len = (unsigned long)ftell(f);
    fclose(f);
    return len;
}

J'ai aussi corrigé votre accolade pour vous ;)

Mise à jour : Ce n'est pas vraiment la meilleure solution. Elle est limitée aux fichiers de 4GB sous Windows et elle est probablement plus lente que l'utilisation d'un appel spécifique à la plateforme comme GetFileSizeEx o stat64 .

0 votes

Oui, vous devriez. Cependant, à moins qu'il n'y ait une raison vraiment impérieuse de ne pas écrire spécifique à la plate-forme, vous devriez probablement juste utiliser un appel spécifique à la plate-forme plutôt que le modèle ouverture/cherche-fin/appel/fermeture.

1 votes

Désolé pour la réponse tardive, mais j'ai un problème majeur ici. L'application se bloque lorsqu'elle accède à des fichiers restreints (comme les fichiers protégés par un mot de passe ou les fichiers système). Existe-t-il un moyen de demander un mot de passe à l'utilisateur lorsque cela est nécessaire ?

0 votes

@Justin, vous devriez probablement ouvrir une nouvelle question spécifique au problème que vous rencontrez, et fournir des détails sur la plate-forme sur laquelle vous êtes, comment vous accédez aux fichiers, et quel est le comportement.

16voto

superjoe30 Points 6876

**Ne faites pas cela ( Pourquoi ? ) :

Je cite le document standard C99 que j'ai trouvé en ligne : "Définir l'indicateur de position de fichier à la fin du fichier, comme avec fseek(file, 0, SEEK_END) a un comportement non défini pour un flux binaire (en raison de la possibilité de caractères nuls à la fin) ou pour tout flux dont le codage dépend de l'état et qui ne se termine pas assurément dans l'état de décalage initial**.

Changez la définition en int pour que les messages d'erreur puissent être transmis, puis utilisez fseek() y ftell() pour déterminer la taille du fichier.

int fsize(char* file) {
  int size;
  FILE* fh;

  fh = fopen(file, "rb"); //binary mode
  if(fh != NULL){
    if( fseek(fh, 0, SEEK_END) ){
      fclose(fh);
      return -1;
    }

    size = ftell(fh);
    fclose(fh);
    return size;
  }

  return -1; //error
}

6 votes

@mezhaka : Ce rapport du CERT est tout simplement faux. fseeko y ftello (ou fseek y ftell si vous n'avez pas le choix et que vous êtes satisfait des limites de taille de fichier avec lesquelles vous pouvez travailler) sont la manière correcte de déterminer la longueur d'un fichier. stat -solutions basées sur la technologie ne fonctionnent pas sur de nombreux "fichiers" (tels que les périphériques de bloc) et ne sont pas portables sur des systèmes non-POSIX-ish.

2 votes

C'est la seule façon d'obtenir la taille du fichier sur de nombreux systèmes non conformes à POSIX (comme mon très minimaliste mbed).

1 votes

Vous ne voulez absolument pas utiliser int ici. ftell renvoie un message signé long qui est un type 64 bits sur de nombreux systèmes 64 bits (mais pas tous). Il n'est toujours que 32 bits sur la plupart des systèmes 32 bits, et vous devez donc ftello avec off_t pour être en mesure de traiter des fichiers volumineux de manière portative. Bien que l'ISO C ait choisi de ne pas définir ce comportement, la plupart des implémentations le font, ce qui fait que cela fonctionne en pratique sur la plupart des systèmes.

4voto

NilObject Points 7874

Si vous êtes d'accord pour utiliser la bibliothèque std c :

#include <sys/stat.h>
off_t fsize(char *file) {
    struct stat filestat;
    if (stat(file, &filestat) == 0) {
        return filestat.st_size;
    }
    return 0;
}

26 votes

Ce n'est pas le standard C. Cela fait partie du standard POSIX, mais pas du standard 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