DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

std:filesystem::file_size Advantages and Differences

While fiding a file's size is not a super crucial part of your app, it is an interesting lesson about some bits of std::filesystem. Let's get started!

Bartłomiej Filipek user avatar by
Bartłomiej Filipek
·
Jan. 23, 19 · Tutorial
Like (2)
Save
Tweet
Share
7.58K Views

Join the DZone community and get the full member experience.

Join For Free

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
  • Aboutstd::variant
  • Aboutstd::any
  • std::string_view Performance and followup
  • C++17 string searchers and followup
  • Conversion utilities - about from_chars.
  • Working with std::filesystem - file_size

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) 
{
    std::cout << ex.what() << '\n';
}

What are the advantages (besides shorter code) over the existing C++ methods? Is this method faster?

File Permissions

The other popular technique that is available in C++ (apart from using third-party APIs) 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?

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 some simple code.

Let’s create a simple file:

std::ofstream sample("hello.txt");
sample << "Hello World!\n";

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)
{
    if (!title.empty())
        std::cout << title << ": ";

    std::cout << "owner: "
      << ((p & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
      << ((p & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
      << ((p & fs::perms::owner_exec) != fs::perms::none ? "x" : "-");
    std::cout << " group: "
      << ((p & fs::perms::group_read) != fs::perms::none ? "r" : "-")
      << ((p & fs::perms::group_write) != fs::perms::none ? "w" : "-")
      << ((p & fs::perms::group_exec) != fs::perms::none ? "x" : "-");
    std::cout << " others: "
      << ((p & fs::perms::others_read) != fs::perms::none ? "r" : "-")
      << ((p & fs::perms::others_write) != fs::perms::none ? "w" : "-")
      << ((p & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
      << '\n';
}

For our file we can see:

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 << "tellgSize: " << testFile.tellg() << '\n';
else
    throw std::runtime_error("cannot read file...");

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());

This shows:

owner: --- group: r-- others: r--

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 perform an “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 << "fsize: " << fsize << '\n';

We’ll get the expected output:

fsize: 13

No matter the permissions of the file, we can read its size.

You can see a demo here @Coliru.

Parent Directory Access

While there’s no need to have read/write/exec rights for the file, we need a parent directory's rights to be correct.

I did one more test and I removed all rights from the "." directory (the place where the file was created):

fs::permissions(".", fs::perms::owner_all,  
                     fs::perm_options::remove);  

auto fsize = fs::file_size(sTempName);
std::cout << "fsize: " << fsize << '\n';

But I only got:

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:

  • (read/write) - read, write, and execute — all modes.
  • (read-only) - read, execute — all modes.

That’s why our demo code won’t work. Disabling read access for a file has no effect.

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.

What’s more, the 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 the demo code here @Coliru.

The test is run N = 10'000 times.

On Coliru (Linux):

filesystem::file_size     : 2543920 in 21 ms.
homemade file_size        : 2543920 in 66 ms.
directory_entry file_size : 2543920 in 13 ms.

On Windows:

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. 

More from the Author:

Bartek recently published a book - "C++17 In Detail"- learn the new C++ Standard in an efficient and practical way. The book contains more than 300 pages filled with C++17 content!

Published at DZone with permission of Bartłomiej Filipek, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • DevSecOps Benefits and Challenges
  • Best Practices for Writing Clean and Maintainable Code
  • Core Machine Learning Metrics
  • Implementing Adaptive Concurrency Limits

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: