fenbf / cppstories-discussions

4 stars 1 forks source link

2024/file-time-cpp20/ #142

Open utterances-bot opened 4 months ago

utterances-bot commented 4 months ago

Displaying File Time in C++: Finally fixed in C++20 - C++ Stories

In this blog post, we’ll examine the potentially simple task of getting and displaying file time. Usually, we can depend on some library or OS-specific code to get that file property. Fortunately, since C++20, we have a reliable and simple technique from the std::filesystem and std::chrono components. Let’s jump in.

https://www.cppstories.com/2024/file-time-cpp20/

aetchevarne commented 4 months ago

A posible solution for the homework

    namespace rng = std::ranges;
    auto dir_entries = fs::directory_iterator(".") | rng::to<std::vector>();
    rng::sort(dir_entries, {}, [](auto& de) {return de.last_write_time();});
    for(auto& d: dir_entries)
        std::println("{}, {}", d.last_write_time(), d.path().native());

(Is directory_entry::last_write_time forced to cache the value?)

fenbf commented 4 months ago

Thanks @aetchevarne! and you have a good question about this case, we can go to https://timsong-cpp.github.io/cppwp/n4950/filesystems#fs.class.directory.entry.general-2 and there's the following spec:

Implementations should store such additional file attributes during directory iteration if their values are available and storing the values would allow the implementation to eliminate file system accesses by directory_entry observer functions ([fs.op.funcs]). Such stored file attribute values are said to be cached.

reaktr4n commented 4 months ago

A possible solution:

#include <iostream>
#include <fstream>
#include <filesystem>
#include <format>
#include <map>
#include <algorithm>
#include <chrono>
#include <thread>

namespace fs = std::filesystem;

int main() {
    std::vector<fs::path> toDelete;
    bool isSortingAscending = false;    
    // create some files...
    for (int i = 0; i < 5; ++i)
    {
        toDelete.emplace_back(std::format("example{}.txt", i));
        std::ofstream(toDelete.back().c_str()) << "Hello, World!";
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    if (isSortingAscending)
    {
        // your code here...
        std::sort(toDelete.begin(), toDelete.end(), [](const fs::path& a, const fs::path& b) {
            return fs::last_write_time(a) < fs::last_write_time(b);
        });
    }
    else
    {
        // your code here...
        std::sort(toDelete.begin(), toDelete.end(), [](const fs::path& a, const fs::path& b) {
            return fs::last_write_time(a) > fs::last_write_time(b);
        });
    }

    for (auto i : toDelete)
    {
        std::filesystem::file_time_type ftime = std::filesystem::last_write_time(i);
        std::cout << std::format("File write time is {}\n", ftime);
    }

    for (auto& f : toDelete)
        fs::remove(f);
}
wiktorwandachowicz commented 4 months ago

Another take at the homework - live link: https://godbolt.org/z/KreqqehMd

    constexpr bool sortascending = true; //false;
    std::sort(toDelete.begin(), toDelete.end(), [] (auto &a, auto& b)
        { 
            auto ftimeA = std::filesystem::last_write_time(a);
            auto ftimeB = std::filesystem::last_write_time(b);
            return sortascending ? (ftimeA < ftimeB) : (ftimeA > ftimeB);
        }
    );

    for (auto &path : toDelete) {
        auto ftime = std::filesystem::last_write_time(path);
        std::cout << "path: " << path << " time: " << ftime << std::endl;
    }