Duplicate possible:
Comment déterminez-vous 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, parce que je veux mettre le contenu du fichier chargé dans une chaîne que j'alloue avec malloc()
. Juste écrire malloc(10000*sizeof(char));
est à mon humble avis une mauvaise idée.
Vous devez chercher à la fin du fichier puis demander le poste:
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
Vous pouvez alors chercher en arrière, par exemple:
fseek(fp, 0L, SEEK_SET);
ou (si vous voulez aller au début)
rewind(fp);
En supposant que votre implémentation prend en charge de manière significative 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
Vous pouvez utiliser stat
(si vous connaissez le nom du fichier) ou fstat
(si vous avez le descripteur de fichier).
Voici un exemple pour stat:
#include <sys/stat.h>
struct stat st;
stat(filename, &st);
size = st.st_size;
Vous pouvez utiliser GetFileSize ou GetFileSizeEx .
Si vous avez le descripteur de fichier, fstat()
renvoie une structure de statistiques contenant 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;
J'ai fini par créer une fonction fsize
courte et agréable (note, pas de vérification d'erreur)
int fsize(FILE *fp){
int prev=ftell(fp);
fseek(fp, 0L, SEEK_END);
int sz=ftell(fp);
fseek(fp,prev,SEEK_SET); //go back to where we were
return sz;
}
C'est un peu ridicule que la bibliothèque standard C n'ait pas une telle fonction, mais je peux comprendre pourquoi ce serait difficile car tous les "fichiers" n'ont pas une taille (par exemple /dev/null
)
Avez-vous envisagé de ne pas calculer la taille du fichier et de simplement agrandir le tableau si nécessaire? Voici un exemple (avec vérification d'erreur ommitted):
#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 présente l’avantage de fonctionner même pour les flux dans lesquels il est impossible d’obtenir la taille du fichier (comme stdin).
Comment utiliser lseek / fseek / stat / fstat pour obtenir la taille du fichier?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
void
fseek_filesize(const char *filename)
{
FILE *fp = NULL;
long off;
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("failed to fopen %s\n", filename);
exit(EXIT_FAILURE);
}
if (fseek(fp, 0, SEEK_END) == -1)
{
printf("failed to fseek %s\n", filename);
exit(EXIT_FAILURE);
}
off = ftell(fp);
if (off == (long)-1)
{
printf("failed to ftell %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fseek_filesize - file: %s, size: %ld\n", filename, off);
if (fclose(fp) != 0)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
fstat_filesize(const char *filename)
{
int fd;
struct stat statbuf;
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
if (fstat(fd, &statbuf) == -1)
{
printf("failed to fstat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] fstat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
if (close(fd) == -1)
{
printf("failed to fclose %s\n", filename);
exit(EXIT_FAILURE);
}
}
void
stat_filesize(const char *filename)
{
struct stat statbuf;
if (stat(filename, &statbuf) == -1)
{
printf("failed to stat %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] stat_filesize - file: %s, size: %lld\n", filename, statbuf.st_size);
}
void
seek_filesize(const char *filename)
{
int fd;
off_t off;
if (filename == NULL)
{
printf("invalid filename\n");
exit(EXIT_FAILURE);
}
fd = open(filename, O_RDONLY, S_IRUSR | S_IRGRP);
if (fd == -1)
{
printf("failed to open %s\n", filename);
exit(EXIT_FAILURE);
}
off = lseek(fd, 0, SEEK_END);
if (off == (off_t)-1)
{
printf("failed to lseek %s\n", filename);
exit(EXIT_FAILURE);
}
printf("[*] seek_filesize - file: %s, size: %lld\n", filename, off);
if (close(fd) == -1)
{
printf("failed to close %s\n", filename);
exit(EXIT_FAILURE);
}
}
int
main(int argc, const char *argv[])
{
int i;
if (argc < 2)
{
printf("%s <file1> <file2>...\n", argv[0]);
exit(0);
}
for(i = 1; i < argc; i++)
{
seek_filesize(argv[i]);
stat_filesize(argv[i]);
fstat_filesize(argv[i]);
fseek_filesize(argv[i]);
}
return 0;
}
Si vous êtes sur Linux, envisagez sérieusement d'utiliser simplement la fonction g_file_get_contents de glib. Il gère tout le code pour charger un fichier, allouer de la mémoire et gérer les erreurs.