std:filesystem::file_size Advantages and Differences
Subtitle: Learning std::filesystem through file_size routines.
Last week I wrote a short post that explained how to use std::filesystem::file_size . Today I’d like to continue and show some significant differences that this new functionality has over the “older” techniques (like reading a file and getting its file position).
We’ll also learn something about permissions and how to manage them in std::filesystem .
Recap
STL before C++17 didn’t contain any direct facilities to work with a filesystem. We could only use third party libraries (like Boost), or system APIs.
With C++17 we have two methods:
- std::uintmax_t std::filesystem::file_size(const std::filesystem::path& p);
- std::uintmax_t std::filesystem::directory_entry::file_size() const;
For example, here’s a code that returns the file size:
try < const auto fsize = std::filesystem::file_size("test.file"); // use fsize. >catch(fs::filesystem_error& ex)
What are the advantages (besides shorter code) over the existing C++ methods? Is this method faster?
The Series
This article is part of my series about C++17 Library Utilities. Here’s the list of the topics in the series:
- Refactoring with std::optional
- Using std::optional
- Error handling and std::optional
- About std::variant
- About std::any
- std::string_view Performance and followup
- C++17 string searchers and followup
- Conversion utilities — about from_chars.
- Working with std::filesystem — file_size
- C++17 In Detail by Bartek!
- C++17 — The Complete Guide by Nicolai Josuttis
- C++ Fundamentals Including C++ 17 by Kate Gregory
- C++17 STL Cookbook by Jacek Galowicz
File Permissions
The other, popular technique that is available in C++ (apart from using third-party API) is to open a file and then read its file position (with tellg() ). The first question we may ask is — how about file permission? What if you cannot open a file? The C++17’s way doesn’t have to open a file, as it reads only file attributes: From cppreference:
For a regular file p, returns the size determined as if by reading the st_size member of the structure obtained by POSIX stat (symlinks are followed)
We can check this with a simple code:
Let’s create a simple file:
std::ofstream sample("hello.txt"); sample
We can read the current file permissions and show them.
// adapted from https://en.cppreference.com/w/cpp/filesystem/permissions void outputPerms(fs::perms p, std::string_view title)
outputPerms(fs::status("hello.txt").permissions());
And we’ll get (On Linux at Coliru):
owner: rw- group: r-- others: r--
We have the right, so tellg() will work as expected:
std::ifstream testFile(std::string("hello.txt"), std::ios::binary | std::ios::ate); if (testFile.good()) std::cout
But how about changing permissions so that we cannot open the file for reading, writing or executing?
fs::permissions(sTempName, fs::perms::owner_all, fs::perm_options::remove); outputPerms(fs::status(sTempName).permissions());
fs::permissions is a method that allows us to set permissions - we pass a flag that we’d like to change (it’s a bitmask) and then “operation” - remove , replace or add .
In our case, I’m removing all owner permissions from the file.
perms::owner_all is composed of owner_read | owner_write | owner_exec .
Now… let’s try to execute the same code that uses tellg() … and we’ll get:
general exception: cannot read file.
But how about fs::file_size ?:
auto fsize = fs::file_size(sTempName); std::cout
We’ll get the expected output:
No matter the permissions of the file (common permissions like read/write/exec), we can read its size.
Parent Directory Access
While there’s no need to have read/write/exec rights for the file, we need a parent directory rights to be correct.
I did one more test and I removed all rights from "." directory (the place were the file was created):
fs::permissions(".", fs::perms::owner_all, fs::perm_options::remove); auto fsize = fs::file_size(sTempName); std::cout
filesystem error! filesystem error: cannot get file size: Permission denied [hello.txt]
You can play with the code here @Coliru
Note For Windows
Windows is not a POSIX system, so it also doesn’t map POSIX file permissions to its scheme. For std::filesystem it only supports two modes:
That’s why our demo code won’t work. Disabling read access for a file does not affect.
Performance
Getting a file size is maybe not the crucial hot-spot in your application… but since we’re C++ programmers, we’d like to know what’s faster… right? 🙂
Since there’s no need to read the file… then std::filesystem methods should be faster… isn’t it?
What’s more, directory_entry method might be even faster as it should be able to cache the results for a single path - so if you want to access that information many times, it’s wiser to use directory_entry .
Here’s a simple test (thanks to Patrice Roy for the initial test example)
you can play with a demo code here @Coliru.
The test is run N = 10'000 times.
filesystem::file_size : 2543920 in 21 ms. homemade file_size : 2543920 in 66 ms. directory_entry file_size : 2543920 in 13 ms.
PS .\Test.exe filesystem::file_size : 1200128 in 81 ms. homemade file_size : 1200128 in 395 ms. directory_entry file_size : 1200128 in 0 ms. PS .\Test.exe filesystem::file_size : 1200128 in 81 ms. homemade file_size : 1200128 in 390 ms. directory_entry file_size : 1200128 in 0 ms.
It’s interesting to see that the directory_entry method is almost no-op in comparison to other techniques. But I haven’t measured the first time access.
Summary
In this blog post, we’ve shed some light over the file_size function. We covered permissions that are required to get the file status and also compared the performance.
While getting a file size is probably not the crucial part of your application it was an interesting lesson about some bits of std::filesystem . In the next posts, I’ll hope to cover more stuff in that area.
I've prepared a valuable bonus if you're interested in Modern C++!
Learn all major features of recent C++ Standards!
Check it out here:
Similar Articles:
See My Books:
Recent Articles
© 2011-2022, Bartlomiej Filipek
Disclaimer: Any opinions expressed herein are in no way representative of those of my employers. All data and information provided on this site is for informational purposes only. I try to write complete and accurate articles, but the web-site will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use.
This site contains ads or referral links, which provide me with a commission. Thank you for your understanding.
Built on the Hugo Platform!
How to get File Size in C++?
Before C++17 we could often complain that even simple tasks as getting a file size were complicated. With std::filesystem things get a bit easier!
Get a File Size
STL before C++17 didn’t contain any direct facilities to work with a filesystem. We could only use third party libraries (like Boost), or system APIs.
To get file size, a popular technique was to open a file and then use file position pointer to compute the size.
Here’s some code that uses stream library:
ifstream testFile("test.file", ios::binary); const auto begin = myfile.tellg(); testFile.seekg (0, ios::end); const auto end = testFile.tellg(); const auto fsize = (end-begin);
Another option was also to open a file in append mode ( std::ios::ate ) and then there was no need to move the file pointer - as it was automatically positioned at the end. On Windows you can also use GetFileSizeEx or FindFirstFileEx (as mentioned in a comment by Artem R.):
HANDLE hFile = /* get file/ open/create */ LARGE_INTEGER size; if (!GetFileSizeEx(hFile, &size)) CloseHandle(hFile); return -1; >
I haven’t explored all of the possible options, so let ma know what is your way of getting file size.
How about C++17? Is there any chance to have a simpler code and maybe portable?
The Series
This article is part of my series about C++17 Library Utilities. Here’s the list of the topics in the series:
- Refactoring with std::optional
- Using std::optional
- Error handling and std::optional
- Everything You Need to Know About std::variant from C++17
- Everything You Need to Know About std::any from C++17
- std::string_view Performance and followup
- C++17 string searchers and followup
- Conversion utilities: on std::from_chars - from a string to a number and on std::to_chars - from numbers into strings
- How to get File Size in C++? and std:filesystem::file_size Advantages and Differences
- How To Iterate Through Directories
- C++17 In Detail by Bartek!
- C++17 - The Complete Guide by Nicolai Josuttis
- C++ Fundamentals Including C++ 17 by Kate Gregory
- Practical C++14 and C++17 Features - by Giovanni Dicanio
- C++17 STL Cookbook by Jacek Galowicz
File Size with std::filesystem
C++17 brings std::filesystem which streamlines a lot of tasks on files and directories. Not only you can quickly get file size, its attributes, but also create new directories, iterate through files, work with path objects.
The new library gives us two functions that we can use:
- std::uintmax_t std::filesystem::file_size( const std::filesystem::path& p );
- std::uintmax_t std::filesystem::directory_entry::file_size() const;
The first function is a free function in std::filesystem , the second one is a method in directory_entry .
Each method also has an overload, as it can throw an exception or return an error code (through an output parameter).
For example, we can get a file size with the following code:
try std::filesystem::file_size("test.file"); > catch(fs::filesystem_error& ex) std::cout <ex.what() <'\n'; >
Or the version with error_codes :
std::error_code ec<>; auto size = std::filesystem::file_size("a.out", ec); if (ec == std::error_code<>) std::cout "size: " size '\n'; else std::cout "error when accessing test file, size is: " size " message: " ec.message() '\n';
You may ask why do we have two methods - as a free function and as a method.
The reason is that directory_entry caches file attributes. That’s why if you iterate over a directory, or you access file several times, then caching might bring performance improvements.
If the file or the directory pointed by directory_entry changes then you need to call the directory_entry::refresh() method to update the cache, otherwise you might get “old” values for your queries.
Demo
You can play with the code in this interactive sample:
Summary
In this short post, you’ve seen how to use file_size function from std::filesystem . I encourage you to explore this new and powerful addition to C++17. If you work with files and directories, this might make your code much more comfortable and portable.
See the next article in the series where I discuss File permissions and performance of file_size : std:filesystem::file_size Advantages and Differences
I've prepared a valuable bonus if you're interested in Modern C++!
Learn all major features of recent C++ Standards!
Check it out here:
Similar Articles:
See My Books:
Recent Articles
© 2011-2022, Bartlomiej Filipek
Disclaimer: Any opinions expressed herein are in no way representative of those of my employers. All data and information provided on this site is for informational purposes only. I try to write complete and accurate articles, but the web-site will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use.
This site contains ads or referral links, which provide me with a commission. Thank you for your understanding.
Built on the Hugo Platform!