0

Is there a way to get the size of a file in C without actually reading the file? I know about fseek but as that sets the 'cursor" to the very end of the file, I'm guessing that does actually read through all of the file.

Am I wrong making this conclusion? Is there a way to do it?

4
  • Which operating system(s) are you targeting? Commented May 5, 2014 at 18:03
  • 2
    There's stat, which would read the file's metadata, and include size info. Commented May 5, 2014 at 18:05
  • 1
    Why is this downvoted? It's a legitimate beginner's question. Commented May 5, 2014 at 18:10
  • @BrianCain Mainly Linux, but it'd be interesting to see how it's done for Windows / other UNIX too. Commented May 5, 2014 at 18:10

2 Answers 2

5

fseek is the portable answer. In any sane implementation, it will read the file's metadata, rather than its content, to determine the end of the file, while refusing to seek in a stream that is not backed by a filesystem that records such data.

There's no other reliable way to get a file's size in pure ISO C than to seek till the end and then rewind; operating systems have specific APIs to do this, e.g. on a POSIX system you can use fstat on the fileno of the FILE* to get the size:

#include <sys/types.h> #include <sys/stat.h> off_t filesize(FILE *fp) { // error checking omitted for clarity int fd = fileno(fp); struct stat sb; fstat(fd, &sb); return sb.st_size; } 
Sign up to request clarification or add additional context in comments.

4 Comments

So fseek doesn't actually keep reading the file till it reaches the end? I'm guessing it still reads the end of the file though?
@JeroenBollen: why would it? The filesystem records the size of the file, so it can read the metadata (inode) and set a pointer appropriately.
After reading I learnt that this function can fail if the file is being output to, or if it's not an actual file (but a stream for example). Are these the only error cases? Can it also fail in a regular write protected file?
@JeroenBollen: on Linux/POSIX/Unix, if you can open the file for reading, you can get its size if it has one. See the man pages for the exact failure conditions; the general advice is always check, and abort whenever you get an error return.
1

I know about fseek but as that sets the 'cursor" to the very end of the file, I'm guessing that does actually read through all of the file.

It does not. For linux, it uses the llseek file operation which will check that the operand is in-range and only set this file descriptor's offset if that check passes. It may need to access the underlying device in order to walk some of the filesystem's data structures, though. But it won't "read" the file in that the operation shouldn't become significantly more expensive with larger files. Technically, that's filesystem-dependent behavior though.

For posix, you could do the following:

get_filesize.h:

#include <stdint.h> uint64_t get_size(const char *filename); 

get_filesize_posix.c:

#include "get_filesize.h" #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> uint64_t get_size(const char *filename) { struct stat s; int ret = stat(filename, &s); if (ret != 0) perror("stat"); return (uint64_t) s.st_size; } 

3 Comments

1) Suggest static uint64_t BLOCK_SIZE_BYTES = 512; to ensure the return product is calculated with uint64_t math. 2) As code return type is uint64_t, where you thinking stat64()?
st_blocks*512 may be larger or smaller than the actual size, because it's rounded up to a multiple of 512, but all-zero blocks are typically not stored and thus not counted.
I'd recommend using identical type to s.st_size. For example, on Linux st_size has type off_t instead of uint64_t (man s stat).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.