Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get file size in ANSI C without fseek and ftell?

While looking for ways to find the size of a file given a FILE*, I came across this article advising against it. Instead, it seems to encourage using file descriptors and fstat.

However I was under the impression that fstat, open and file descriptors in general are not as portable (After a bit of searching, I've found something to this effect).

Is there a way to get the size of a file in ANSI C while keeping in line with the warnings in the article?

like image 655
math4tots Avatar asked Mar 22 '12 21:03

math4tots


People also ask

How do I determine file size?

Right-click the file and click Properties. The image below shows that you can determine the size of the file or files you have highlighted from in the file properties window. In this example, the chrome. jpg file is 18.5 KB (19,032 bytes), and that the size on disk is 20.0 KB (20,480 bytes).

Which function should you use to determine the size of a file?

The filesize() function returns the size of a file.

Which library function can be used to find the size of a file?

The idea is to use fseek() in C and ftell in C. Using fseek(), we move file pointer to end, then using ftell(), we find its position which is actually size in bytes.


2 Answers

In standard C, the fseek/ftell dance is pretty much the only game in town. Anything else you'd do depends at least in some way on the specific environment your program runs in. Unfortunately said dance also has its problems as described in the articles you've linked.

I guess you could always read everything out of the file until EOF and keep track along the way - with fread() for example.

like image 122
Carl Norum Avatar answered Oct 12 '22 12:10

Carl Norum


The article claims fseek(stream, 0, SEEK_END) is undefined behaviour by citing an out-of-context footnote.

The footnote appears in text dealing with wide-oriented streams, which are streams that the first operation that is performed on them is an operation on wide-characters.

This undefined behaviour stems from the combination of two paragraphs. First §7.19.2/5 says that:

— Binary wide-oriented streams have the file-positioning restrictions ascribed to both text and binary streams.

And the restrictions for file-positioning with text streams (§7.19.9.2/4) are:

For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET.

This makes fseek(stream, 0, SEEK_END) undefined behaviour for wide-oriented streams. There is no such rule like §7.19.2/5 for byte-oriented streams.

Furthermore, when the standard says:

A binary stream need not meaningfully support fseek calls with a whence value of SEEK_END.

It doesn't mean it's undefined behaviour to do so. But if the stream supports it, it's ok.

Apparently this exists to allow binary files can have coarse size granularity, i.e. for the size to be a number of disk sectors rather than a number of bytes, and as such allows for an unspecified number of zeros to magically appear at the end of binary files. SEEK_END cannot be meaningfully supported in this case. Other examples include pipes or infinite files like /dev/zero. However, the C standard provides no way to distinguish between such cases, so you're stuck with system-dependent calls if you want to consider that.

like image 36
R. Martinho Fernandes Avatar answered Oct 12 '22 13:10

R. Martinho Fernandes