Thursday, February 3, 2011

How do you determine the size of a file in C?

How can I figure out the size of a file, in bytes?

#include <stdio.h>

unsigned int fsize(char* file){
  //what goes here?
}
  • You're going to need to use a library function to retrieve the details of a file. As C is completely platform independent, you're going to need to let us know what platform / operating system you're developing for!

  • as long as you have "iostream" available, you can do the following:

    unsigned int fsize(char* file){
      long begin,end;
      ifstream myfile (file);
      begin = myfile.tellg();
      myfile.seekg (0, ios::end);
      end = myfile.tellg();  
      return end-begin;
    }
    

    is the idea. My C++ chops are a little creaky, so pushing a char* to an ifstream might not work as I wrote it... a good look at tellg() and seekg() will help you get the details.

  • If you're fine with using the std c library:

    #include <sys/stat.h>
    off_t fsize(char *file) {
        struct stat;
        if (stat(file, &stat) == 0) {
            return stat.st_size;
        }
        return 0;
    }
    
    From NilObject
  • You can open the file, go to 0 offset relative from the bottom of the file with

    #define SEEKBOTTOM   2
    
    fseek(handle, 0, SEEKBOTTOM)
    

    the value returned from fseek is the size of the file.

    I didn't code in C for a long time, but I think it should work.

    sigjuice : You shouldn't have to define something like SEEKBOTTOM. #include fseek(handle, 0, SEEK_END);
    From PabloG
  • Matt's solution should work, except that it's C++ instead of C, and the initial tell shouldn't be necessary.

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

    Fixed your brace for you, too. ;)

    From Derek Park
  • Don't do this (why?):

    Change the definition to int so that error messages can be transmitted, and then use fseek() and ftell() to determine the file size.

    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
    }
    
    mezhaka : Here is the report that unequivocally states that you should not do that: FIO19-C. Do not use fseek() and ftell() to compute the size of a file. It would be nice if you add this link to your answer, so the other people could see that clearly.
    superjoe30 : thanks. how's that?
    R.. : @mezhaka: That CERT report is simply wrong. `fseeko` and `ftello` (or `fseek` and `ftell` if you're stuck without the former and happy with limits on the file sizes you can work with) are the correct way to determine the length of a file. `stat`-based solutions **do not work** on many "files" (such as block devices) and are not portable to non-POSIX-ish systems.
    From superjoe30
  • A quick search in Google found a method using fseek and ftell and a thread with this question with answers that it can't be done in just C in another way.

    You could use a portability library like NSPR (the library that powers Firefox) or check its implementation (rather hairy).

    From Nickolay
  • @NilObject That's not standard C. It's part of the POSIX standard, but not the C standard.

    From Derek Park
  • Don't use int. Files over 2 gigabytes in size are common as dirt these days

    Don't use unsigned int. Files over 4 gigabytes in size are common as some slightly-less-common dirt

    IIRC the standard library defines off_t as an unsigned 64 bit integer, which is what everyone should be using. We can redefine that to be 128 bits in a few years when we start having 16 exabyte files hanging around.

    If you're on windows, you should use GetFileSizeEx - it actually uses a signed 64 bit integer, so they'll start hitting problems with 8 exabyte files. Foolish Microsoft! :-)

  • And if you're building a Windows app, use the GetFileSizeEx API as CRT file I/O is messy, especially for determining file length, due to peculiarities in file representations on different systems ;)

    From James D
  • Based on NilObject's code:

    #include <sys/stat.h>
    
    off_t fsize(const char *filename) {
        struct stat st; 
    
        if (stat(filename, &st) == 0)
            return st.st_size;
    
        return -1; 
    }
    

    Changes:

    • Made the filename argument a const char.
    • Corrected the struct stat definition, which was missing the variable name.
    • Returns -1 on error instead of 0, which would be ambiguous for an empty file. off_t is a signed type so this is possible.

    If you want fsize() to print a message on error, you can use this:

    #include <sys/stat.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;
    }
    

    On 32-bit systems you should compile this with the option -D_FILE_OFFSET_BITS=64, otherwise off_t will only hold values up to 2 GB. See the "Using LFS" section of Large File Support in Linux for details.

    Drew Hall : This is Linux/Unix specific--probably worth pointing that out since the question didn't specify an OS.
    Ted Percival : You could probably change the return type to ssize_t and cast the size from an off_t without any trouble. It would seem to make more sense to use a ssize_t :-) (Not to be confused with size_t which is unsigned and cannot be used to indicate error.)

0 comments:

Post a Comment