105

I'm sure I've just missed this in the manual, but how do you determine the size of a file (in bytes) using C++'s istream class from the fstream header?

1
  • 1
    @NarendraN - that doesn't use fstream, as this question explicitly asks for Commented Dec 30, 2021 at 15:45

6 Answers 6

111

You can open the file using the ios::ate flag (and ios::binary flag), so the tellg() function will directly give you directly the file size:

ifstream file( "example.txt", ios::binary | ios::ate); return file.tellg(); 
Sign up to request clarification or add additional context in comments.

5 Comments

@Dominik Honnef: in VS 2013 Update5 64 bit this approach, with ios:ate flag and without seekg(0, ios:end) might not work for large files. See stackoverflow.com/questions/32057750/… for more information.
@displayName cplusplus.com kind of disagrees with that statement: it indeed uses tellg() to detect filesize.
the answer below works in all situations and not this one, since it returns 0 in lot of cases when the pointer is at the beginning of the file
This is a totally incorrect answer and gives 0 in many cases.
73

You can seek until the end, then compute the difference:

std::streampos fileSize( const char* filePath ){ std::streampos fsize = 0; std::ifstream file( filePath, std::ios::binary ); fsize = file.tellg(); file.seekg( 0, std::ios::end ); fsize = file.tellg() - fsize; file.close(); return fsize; } 

18 Comments

Out of interest, is the first call to tellg not guaranteed to return 0?
I wonder why in the 21st century we still have to count the size of the stream manually? Why don't the commitee just make a function for that which everybody could use? Isn't it just that simple? Are there any hidden caveats?
@rightaway717: They could. But why? C++ is not a language where "everything is done for you". It provides the building blocks then it's up to you to do whatever you want with them. It would be a complete waste of time to create a function to serve just this one specific use case. Besides, a simple "getter" could easily mislead people into not realising that a file seek is involved, which may have ramifications for them in all sorts of cases. It's better to have people do this explicitly.
@LightnessRacesinOrbit: while I do understand what you mean, I still do not agree. Many other functions are also that primitive to serve their specific usecase, like get the length of a string. This is a pretty common operation to get the size of things to make a function for it. I believe you do it as well in your code - provide a function to know the size of your own classes, if size has a meaning for them.There are also plenty of function that do a (potentially) long operation under the hood, like vector resizing for example. that doesn't mean that we have to make people do it explicitly.
@LightnessRacesinOrbit, on most systems getting the file size by subtracting offests returned by tell's operations is a slower operation than just directly getting the size of the file which is stored somewhere in the inode or similar structure in the filesystem itself. So, whilst the fallback algorithm could be the one that uses seek's and tell's, an optimized implementation could work around that and provide a faster approach. How's that a bad thing?
|
48

Don't use tellg to determine the exact size of the file. The length determined by tellg will be larger than the number of characters can be read from the file.

From stackoverflow question tellg() function give wrong size of file? tellg does not report the size of the file, nor the offset from the beginning in bytes. It reports a token value which can later be used to seek to the same place, and nothing more. (It's not even guaranteed that you can convert the type to an integral type.). For Windows (and most non-Unix systems), in text mode, there is no direct and immediate mapping between what tellg returns and the number of bytes you must read to get to that position.

If it is important to know exactly how many bytes you can read, the only way of reliably doing so is by reading. You should be able to do this with something like:

#include <fstream> #include <limits> ifstream file; file.open(name,std::ios::in|std::ios::binary); file.ignore( std::numeric_limits<std::streamsize>::max() ); std::streamsize length = file.gcount(); file.clear(); // Since ignore will have set eof. file.seekg( 0, std::ios_base::beg ); 

1 Comment

My... I guess I'll continue to use stat().
13

Since C++17, we have std::filesystem::file_size. This doesn't strictly speaking use istream or fstream but is by far the most concise and correct way to read a file's size in standard C++.

#include <filesystem> ... auto size = std::filesystem::file_size("example.txt"); 

4 Comments

After running benchmarks, I realize it's also running much faster than the istream variant, on Windows at least.
Does it return the actual file size or the file size determined by the OS? The OS will report a size bigger than the actual size, since most OSs use blocks for space
@Raildex filesize returns the size determined as if by reading the st_size member of the structure obtained by POSIX. Copied from en.cppreference.com/w/cpp/filesystem/file_size
Unfortunately this answer is flawed for security purposes. It's possible for an exploit to replace "example.txt" for a different file between the call to file_size and opening it; aka a race condition. The only safe option is one where the file size is obtained from pinging the internal file descriptor.
11

Like this:

long begin, end; ifstream myfile ("example.txt"); begin = myfile.tellg(); myfile.seekg (0, ios::end); end = myfile.tellg(); myfile.close(); cout << "size: " << (end-begin) << " bytes." << endl; 

2 Comments

You may want to use the more appropriate std::streampos instead of long as the latter may not support as large a range as the former - and streampos is more than just an integer.
Isn't your begin just 0?
-9

I'm a novice, but this is my self taught way of doing it:

ifstream input_file("example.txt", ios::in | ios::binary) streambuf* buf_ptr = input_file.rdbuf(); //pointer to the stream buffer input.get(); //extract one char from the stream, to activate the buffer input.unget(); //put the character back to undo the get() size_t file_size = buf_ptr->in_avail(); //a value of 0 will be returned if the stream was not activated, per line 3. 

1 Comment

all this does is determine if there is a first character. How does that help?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.