Recently I got curious to explore the methods that are available to find out a file's size in C++. The first (easiest?) method that I had learned a long time ago is using tellg(). Let's see an example:
Simple. First, a file stream is opened with ios::ate flag which sets the stream's position indicator at the end of the file. Then, tellg() is used to retrieve this position index.
Back then, this was the only method I used to find a file's size. However, in some cases it would be handy to be able to retrieve a file's size without having to open the file. Other than that, some say that if the file has been opened in binary mode, sometimes the returned size could be incorrect(?).
Whether the latter fact is true or not, opening a file just to determine it's size doesn't seem to be the best approach. What other method is available, then?
An alternative approach is to use the stat struct. Let's see it in action:
I know! struct stat st; looks like C! In C++ you don't need to write struct every time you want to declare a structure instance. However, notice that in <sys/stat.h>, there is also a function with the same name. Without the extra struct in front of it, the compiler comes up with an error because it mistakenly tries to consider the function.
The stat method works without the need to open the file. However, your code becomes platform-dependent to some degree. The stat function and struct are available in POSIX-based systems. In Windows, however, the equivalent is _stat. Given that, it's not difficult to write a function that works on both platforms alike, with a little bit of macro help:
If you check Boost's filesystem library, you will find it's file_size function is using the stat approach. Until a filesystem library is added to the C++ standard (hopefully!), the better approach to determine a file's size seems to be the stat method, whether you use Boost or a function like above.
It would be interesting for me to see if the above code works in Visual Studio and Mac OS X as well, as the only platform I currently have access to is GNU/Linux. Please share your result if you test it.
Reference on macros used: here
#include <iostream> #include <fstream> using namespace std; int main() { ifstream file("test", ios::ate); streampos size = file.tellg(); cout<<"File size for \"test\" is: "<<size<<" bytes."<<endl; return 0; }
Simple. First, a file stream is opened with ios::ate flag which sets the stream's position indicator at the end of the file. Then, tellg() is used to retrieve this position index.
Back then, this was the only method I used to find a file's size. However, in some cases it would be handy to be able to retrieve a file's size without having to open the file. Other than that, some say that if the file has been opened in binary mode, sometimes the returned size could be incorrect(?).
Whether the latter fact is true or not, opening a file just to determine it's size doesn't seem to be the best approach. What other method is available, then?
An alternative approach is to use the stat struct. Let's see it in action:
#include <iostream> #include <sys/stat.h> using namespace std; int main() { struct stat st; stat("test", &st); cout<<"File size for \"test\" is: "<<st.st_size<<" bytes."<<endl; return 0; }
I know! struct stat st; looks like C! In C++ you don't need to write struct every time you want to declare a structure instance. However, notice that in <sys/stat.h>, there is also a function with the same name. Without the extra struct in front of it, the compiler comes up with an error because it mistakenly tries to consider the function.
The stat method works without the need to open the file. However, your code becomes platform-dependent to some degree. The stat function and struct are available in POSIX-based systems. In Windows, however, the equivalent is _stat. Given that, it's not difficult to write a function that works on both platforms alike, with a little bit of macro help:
#include <iostream> #include <string> #include <stdexcept> #include <sys/stat.h> long int file_size(const std::string& file_name) { #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #define STAT_IDENTIFIER stat //for MacOS X and other Unix-like systems #elif defined(_WIN32) #define STAT_IDENTIFIER _stat //for Windows systems, both 32bit and 64bit? #endif struct STAT_IDENTIFIER st; if(STAT_IDENTIFIER(file_name.c_str(), &st) == -1) { throw std::runtime_error("stat error!"); } return st.st_size; } using namespace std; int main() { try { cout<<"File size for \"test\" is: "<<file_size("test")<<" bytes."<<endl; } catch(const exception& e) { cerr<<e.what()<<endl; } return 0; }
If you check Boost's filesystem library, you will find it's file_size function is using the stat approach. Until a filesystem library is added to the C++ standard (hopefully!), the better approach to determine a file's size seems to be the stat method, whether you use Boost or a function like above.
It would be interesting for me to see if the above code works in Visual Studio and Mac OS X as well, as the only platform I currently have access to is GNU/Linux. Please share your result if you test it.
Reference on macros used: here
11 Comments On This Entry
Page 1 of 1

Martyr2
16 August 2015 - 03:00 PM
I can confirm that this function works on Windows 7 with Visual Studio 2013.

CTphpnwb
16 August 2015 - 06:19 PM
This works — sort of — in OS X using Xcode. If I use the code as is, and there is a file named test then I get the run time error stat error!. If I rename the file test.txt and use that in the code, I get the correct file size.

CTphpnwb
16 August 2015 - 07:57 PM
By the way, it doesn't seem to matter what extension I use, as long as I use one!

CTphpnwb
17 August 2015 - 07:13 PM
Same issue with that version. It succeeds as long as an extension is used and fails if one isn't. The extension used in the code has to match the one on the file.

CTphpnwb
20 August 2015 - 08:25 AM
OS X does allow files with no extension. It's the code that's having trouble seeing it.
#include <iostream> #include <string> #include <stdexcept> #include <sys/stat.h> #include <fstream> long int file_size(const std::string& file_name) { #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #define STAT_IDENTIFIER stat //for MacOS X and other Unix-like systems #elif defined(_WIN32) #define STAT_IDENTIFIER _stat //for Windows systems, both 32bit and 64bit? #endif struct STAT_IDENTIFIER st; if(STAT_IDENTIFIER(file_name.c_str(), &st) == -1) { perror(nullptr); throw std::runtime_error("stat error!"); } return st.st_size; } using namespace std; int main() { try { cout<<"File size for \"test\" is: "<<file_size("test")<<" bytes."<<endl; } catch(const exception& e) { cerr<<e.what()<<endl; } ifstream file("test", ios::ate); streampos size = file.tellg(); cout<<"File size for \"test\" is: "<<size<<" bytes."<<endl; return 0; }
Quote
No such file or directory
File size for "test" is: stat error!
File size for "test" is: -1 bytes.
File size for "test" is: stat error!
File size for "test" is: -1 bytes.

CTphpnwb
20 August 2015 - 10:27 AM
Oh crap! I was using the Finder to "rename" the file, but it was just hiding the extension, not actually removing it. When I removed the extension it worked.

Page 1 of 1
← February 2021 →
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
Tags
Recent Entries
-
-
Determining a file's size in C++
on Aug 14 2015 06:16 PM
-
-
-
My Blog Links
Recent Comments
Search My Blog
2 user(s) viewing
2 Guests
0 member(s)
0 anonymous member(s)
0 member(s)
0 anonymous member(s)