What is the most appropriate way of ensuring that a string (user input) is a valid text file path? And also the extension part should be either .txt or empty.
I have considered two approaches:
const std::string_view filename {"setup"};
// Check if the filename is valid
std::error_code ec;
if (!std::filesystem::path(filename).has_filename() || !std::filesystem::exists(filename, ec) ||
std::filesystem::path(filename).extension() != "" && std::filesystem::path(filename).extension() != ".txt")
{
return false;
}
or:
const std::string_view filename {"setup"};
// Check if the filename is valid
if (std::filesystem::path(filename).extension() != "" && std::filesystem::path(filename).extension() != ".txt")
{
return false;
}
std::istream ifs { filename };
if (!ifs.is_open()) // or if (!ifs) or if (ifs.fail())
{
return false;
}
I have to mention that exists() is not what I want though since I would rather directly open the file for a read operation using an ifstream (instead of checking for its existence first).
There is also a function named is_regular_file() which I guess I need to add to the above checks.
Is the second approach sufficient for handling any potential errors (e.g. invalid characters used in the user input, wrong extension, file not opening, wrong file type, etc)?
A file might exist, but you cannot tell (programmatically or not) because you (or the executable) simply lack the appropriate permissions.
std::filesystem::exists is your best option for checking existence. As for checking the extension, std::filesystem::path::extension is a good place to start.
You can sure try. Just make sure the stream is valid before you try reading anything from it. Your sample of
!ifsis my personal preference; the stream has an implicit boolean conversion which returnsfalseif it's invalid.One note: you should avoid repeatedly calling
std::filesystem::path(filename). This constructs a newpathinstance each time. Construct one, and then interrogate it as necessary.