Recommended way of passing file paths
-
Hi!
in the codebase I am working on, filepaths are passed as QString parameters most of the time. In some cases it is also a combination of QDir and QString.
Examples:
void foo(const QString &filename); void foo(const QDir pathToFile, const QString &filename);
In order to use stronger types for the interfaces, I was considering the following types:
- QString
- QDir
- QFile
- QFileInfo
- QUrl
- std::filesystem::path
QString
This is the simplest, with the disadvantage that the type itself does not even tell that it is a path.QDir
Compared to QString we know that a path is passed. But still, it could be a path to a directory or a path to a file. Also the name QDir seems to be misleading for passing paths to files.QFile
For QFile it is clear that it is about a file, not about a directory. The thing I don't like about this is that it opens up other questions, such as "Should the passed file be opened before passing it? Does it need to exist?"QFileInfo
This seems to fit better than QFile, as it is a more lightweight class which is not used for modifying the file.QUrl
To me, this seems to be a too general-purpose class for passing file paths around.std::filesystem::path
This looks like it is a good equivalent to QDir. What I like, is that the name does not suggest that it is a directory. However I am not sure if mixing Qt and std:: classes here could cause other troubles i.e. native file paths.Is there a recommended way for passing filepaths as parameters? Any thoughts are highly appreciated.
My goal would be to have a guideline saying: When passing a path to a file, use class XYZ. -
I am not sure I have the perfect answer, but lets try to narrow it down (basically agreeing with you).
QFile is a file and not a file path. It does inherit from QIODevice. It is meant for input/output and might even be total overkill to just store a file path. Don't use it for this.
QFileInfo gives you more information about a file. You can split it up into its separate parts (base name, extension, path, etc.). Still, I don't see it as the right way to pass just a file path around. I personally use it only when I need the extra information on a file path provided as string.
QUrl: Just as you said, it seems like it is overkill. Technically, it would be perfect to represent file paths. But, it does a lot more than just to represent file paths. This might actually confuse people as they might assume that their code needs to support more than just files.
std::filesystem::path seems to be perfect when you are in STL world. As soon as you want to use it for opening a QFile, though, you have the whole trouble of converting std::string to QString. If you tend to use temporaries, you'll get into trouble sooner or later. If you have the choice, try to not mix std::string and QString. Stay in Qt land. (There is also the huge question if std::string is UTF-8 or in the user's locale. Within Qt this is handled correctly as QString knows the character encoding.)
This leaves us with QString and QDir. I am not sure which one would be the best. I personally use QString. One thing to consider is that initially you have a QString (from user input or read from a file) which you then use to open a file. Under normal circumstances there is no reason to convert the original QString to a QDir just to pass it around and then convert it back to a QString, as QFile's constructor wants a QString again. QDir only comes in handy when you want to manipulate the path. Also note that Qt's file dialog returns a QString! So, Qt made up their mind to use a QString (though, this decision is quite old and there might be better options now).
-
@christian_p said in Recommended way of passing file paths:
with the disadvantage that the type itself does not even tell that it is a path
Doesn't the parameter name tell you that it should be a path/filename?
Most of the time paths are handled as strings as there is no benefit in using anything else. -
@jsulm Yes, the filename tells you that. But I thought there might be a fitting type, so that I could rely on a strong type rather than on parameter names.
In my experience by using QString it is hard to disambiguate, whether the parameter is just the base filename, or a file path (directory + filename).The things that got me thinking was methods that were passing a QDir and a QString for it's filename, or in some places there were structs holding a QDir and a QString.
-
@christian_p
You can do all this typing if you want, but my experience is like @jsulm says, it's not worth the effort over just using aQString
, and getting your code right.I might store, say, a temperature. I'll just use a
double
(orfloat
/int
). You could then say "but the type doesn't tell me it's a temperature". And so on. -
@christian_p If you need to disambiguate you can still use QFileInfo at the time you use the path.
QFileInfo fi(filepath); if ( fi.isFile() ) { ... }
-
I am not sure I have the perfect answer, but lets try to narrow it down (basically agreeing with you).
QFile is a file and not a file path. It does inherit from QIODevice. It is meant for input/output and might even be total overkill to just store a file path. Don't use it for this.
QFileInfo gives you more information about a file. You can split it up into its separate parts (base name, extension, path, etc.). Still, I don't see it as the right way to pass just a file path around. I personally use it only when I need the extra information on a file path provided as string.
QUrl: Just as you said, it seems like it is overkill. Technically, it would be perfect to represent file paths. But, it does a lot more than just to represent file paths. This might actually confuse people as they might assume that their code needs to support more than just files.
std::filesystem::path seems to be perfect when you are in STL world. As soon as you want to use it for opening a QFile, though, you have the whole trouble of converting std::string to QString. If you tend to use temporaries, you'll get into trouble sooner or later. If you have the choice, try to not mix std::string and QString. Stay in Qt land. (There is also the huge question if std::string is UTF-8 or in the user's locale. Within Qt this is handled correctly as QString knows the character encoding.)
This leaves us with QString and QDir. I am not sure which one would be the best. I personally use QString. One thing to consider is that initially you have a QString (from user input or read from a file) which you then use to open a file. Under normal circumstances there is no reason to convert the original QString to a QDir just to pass it around and then convert it back to a QString, as QFile's constructor wants a QString again. QDir only comes in handy when you want to manipulate the path. Also note that Qt's file dialog returns a QString! So, Qt made up their mind to use a QString (though, this decision is quite old and there might be better options now).
-
@SimonSchroeder
QDir
is only for directories, not for files. So it is not a (suitable) candidate for general "file paths".