2

Motivating example:

In a previous session, the application has stored some path selected by the user. In the meantime that path may have been deleted, moved, renamed or the drive unmounted. The application would now like to let the user browse for a path via a QFileDialog and for the user's convenience, the previous path is passed as the starting directory of the file dialog, as presumably the new path is likely to be near the old path. Unfortunately, if QFileDialog is given a starting path that does not exist, it defaults to the current working directory, which is very unlikely to be helpful to the user as it is typically the installation directory of the application.

So we would like to preprocess the old path to point to a directory that actually exists before passing it to QFileDialog. If the old path doesn't exist, we'd like to replace it with the nearest directory that does.

So how does one take a file path (which may or may not exist) and search "up" that path until one finds something that actually exists in the filesystem?

Parker Coates
  • 8,520
  • 3
  • 31
  • 37
  • Your question is a bit unclear, at least for me. The title says "file path that actually exists" but the body says "file path which may or may not exist". However, if I understand correctly, the goal is to **get the (absolute path to the) parent directory of the specified file path**, am I right? – kefir500 Oct 12 '18 at 06:06
  • @kefir500, I agree that the question is confusingly worded, but no, your understanding is not correct. I'll edit the question. – Parker Coates Oct 12 '18 at 12:10

2 Answers2

2

These are the two approaches I've come up with so far, but suggestions for improvement would be very much appreciated.

Searching upward until a path exists:

QString GetNearestExistingAncestorOfPath(const QString & path)
{
    if(QFileInfo::exists(path)) return path;

    QDir dir(path);
    if(!dir.makeAbsolute()) return {};
    do
    {
        dir.setPath(QDir::cleanPath(dir.filePath(QStringLiteral(".."))));
    }
    while(!dir.exists() && !dir.isRoot());

    return dir.exists() ? dir.path() : QString{};
}

Searching downward until a path doesn't exist:

QString GetNearestExistingAncestorOfPath(const QString & path)
{
    if(QFileInfo::exists(path)) return path;

    auto segments = QDir::cleanPath(path).split('/');
    QDir dir(segments.takeFirst() + '/');
    if(!dir.exists()) return {};
    for(const auto & segment : qAsConst(segments))
    {
        if(!dir.cd(segment)) break;
    }
    return dir.path();
}
Parker Coates
  • 8,520
  • 3
  • 31
  • 37
1

Try the following code:

QString getNearestExistingPath(const QString &path)
{
    QString existingPath(path);
    while (!QFileInfo::exists(existingPath)) {
        const QString previousPath(existingPath);
        existingPath = QFileInfo(existingPath).dir().absolutePath();
        if (existingPath == previousPath) {
            return QString();
        }
    }
    return existingPath;
}

This function utilizes the QFileInfo::dir() method which returns the parent directory for a specified path. The code is looped until the existing path is met or the paths in the two latest iterations are identical (this helps us to avoid the infinite loop).

From the QFileInfo::dir() docs:

Returns the path of the object's parent directory as a QDir object.
Note: The QDir returned always corresponds to the object's parent directory, even if the QFileInfo represents a directory.

I still recommend you to run some tests because I may be missing something.

kefir500
  • 4,184
  • 6
  • 42
  • 48