Home > Software design >  How to test if a provided path contains a file or it's just a directory
How to test if a provided path contains a file or it's just a directory

Time:04-08

Why is boost::is_regular_file returning false? I am running the following code on wandbox.org

#include <boost/filesystem.hpp>
#include <iostream>
namespace filesys = boost::filesystem;

int main(){
    filesys::path pathObj("used/for/test/DoesNotExist.json");
    std::cout <<"is file "<< filesys::is_regular_file(pathObj) << std::endl;
    return 0;
}

CodePudding user response:

This is the specified behaviour.

is_regular_file(p) is equivalent to s.type() == file_type::regular

Notes
The throwing overload is additionally specified to throw std::filesystem::filesystem_error if status(p) would throw

status(p)
If p does not exist, returns file_status(file_type::not_found)

file_type::not_found == file_type::regular is false.

CodePudding user response:

I want to test if it's a path containing a file or not. Regardless if the file exists or not. Just Is – Hani Gotc 34 mins ago

Unless a file exists it can be either. It could even be a fifo, device node or UNIX domain socket. That's because the name means nothing about the type.

Simple demo: Live On Coliru

#include <boost/filesystem.hpp>
#include <iostream>
#include <iomanip>
namespace fs = boost::filesystem;
using boost::filesystem::path;

static inline std::ostream& operator<<(std::ostream& os, fs::file_type t) {
    switch (t) {
        case fs::file_type::block_file:     return os << "block_file";
        case fs::file_type::character_file: return os << "character_file";
        case fs::file_type::directory_file: return os << "directory_file";
        case fs::file_type::fifo_file:      return os << "fifo_file";
        case fs::file_type::file_not_found: return os << "file_not_found";
        case fs::file_type::regular_file:   return os << "regular_file";
        case fs::file_type::reparse_file:   return os << "reparse_file";
        case fs::file_type::socket_file:    return os << "socket_file";
        case fs::file_type::symlink_file:   return os << "symlink_file";
        case fs::file_type::status_unknown: return os << "unknown/status error";
        case fs::file_type::type_unknown:
        default: return os << "unknown";
    }
}

#define ACTION(statement)                                                      \
    statement;                                                                 \
    std::cout << " ----- " << std::setw(50) << #statement << " "               \
              << std::boolalpha;                                               \
    std::cout << "type(): " << status(spec).type() << std::endl;               \
    // std::cout << "is_regular_file(): " << is_regular_file(spec) << std::endl;

int main(){
    ACTION(path spec("used/for/test/DoesNotExist.json"));

    ACTION(create_directories(spec.parent_path()));

    ACTION(create_directory(spec));
    ACTION(remove(spec));

    ACTION(std::ofstream(spec.native()));
    ACTION(remove(spec));

    path temp = fs::unique_path("/tmp/stackoverflow-%%%%%.tmp");
    std::cout << "(temp = " << temp << ")\n";
    ACTION(create_symlink(temp, spec));
    ACTION(std::ofstream(temp.native()));
    ACTION(remove(temp));
    ACTION(remove(spec));

    ACTION(create_symlink(fs::temp_directory_path(), spec));
    ACTION(remove(spec));
}

Prints e.g.

 -----       path spec("used/for/test/DoesNotExist.json") type(): file_not_found
 -----             create_directories(spec.parent_path()) type(): file_not_found
 -----                             create_directory(spec) type(): directory_file
 -----                                       remove(spec) type(): file_not_found
 -----                       std::ofstream(spec.native()) type(): regular_file
 -----                                       remove(spec) type(): file_not_found
(temp = "/tmp/stackoverflow-e4bcc.tmp")
 -----                         create_symlink(temp, spec) type(): file_not_found
 -----                       std::ofstream(temp.native()) type(): regular_file
 -----                                       remove(temp) type(): file_not_found
 -----                                       remove(spec) type(): file_not_found
 -----    create_symlink(fs::temp_directory_path(), spec) type(): directory_file
 -----                                       remove(spec) type(): file_not_found

As you can see the file type changes depending on the situation.

Alternative

Perhaps you want to respond to the common naming convention where directory filenames have no extension:

Live On Coliru

#include <boost/filesystem.hpp>
#include <iostream>
using boost::filesystem::path;

int main() {
    for (path p : {
             "used/for/test/DoesNotExist.json",
             "used/for/test",
             "used/for/test/",
         })
        std::cout << p << " has extension: " << std::boolalpha
                  << p.has_extension() << " (" << p.extension() << ")\n";
}

Prints

"used/for/test/DoesNotExist.json" has extension: true (".json")
"used/for/test" has extension: false ("")
"used/for/test/" has extension: false ("")
  • Related