tags:

views:

3356

answers:

11

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

#include <stdio.h>

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

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!

Chris Roberts
A: 

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.

Matt Dunnam
+5  A: 

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;
}
NilObject
A: 

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.

PabloG
You shouldn't have to define something like SEEKBOTTOM.#include <stdio.h>fseek(handle, 0, SEEK_END);
sigjuice
+2  A: 

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. ;)

Derek Park
+4  A: 

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
}
superjoe30
Here is the report that unequivocally states that you should not do that: <a href="https://www.securecoding.cert.org/confluence/x/QwCMAg">FIO19-C. Do not use fseek() and ftell() to compute the size of a file</a>. It would be nice if you add this link to your answer, so the other people could see that clearly.
mezhaka
thanks. how's that?
superjoe30
@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.
R..
+1  A: 

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).

Nickolay
+1  A: 

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

Derek Park
+10  A: 

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! :-)

Orion Edwards
+1  A: 

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 ;)

James D
+10  A: 

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.

Ted Percival
This is Linux/Unix specific--probably worth pointing that out since the question didn't specify an OS.
Drew Hall
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.)
Ted Percival