Get the path from a QML url

2019-02-06 14:44发布

问题:

FileDialog gives a QML url variable. theurl.toString() gives something like file:///c:\foo\bar.txt. How do I get c:\foo\bar.txt?

I want to do it in a cross-platform way, and ideally without relying on regex-style hacks. QUrl provides a path() method, but I don't seem to be able to access it from QML.

回答1:

As noted in the comments already, there seems to be no way (yet?) to get the path itself without a regex. So this is the only way to go:

Basic solution

FileDialog {
    onAccepted: {
        var path = myFileDialog.fileUrl.toString();
        // remove prefixed "file:///"
        path = path.replace(/^(file:\/{3})/,"");
        // unescape html codes like '%23' for '#'
        cleanPath = decodeURIComponent(path);
        console.log(cleanPath)
    }
}

This regex should be quite robust as it only removes the file:/// from the beginning of the string.

You will also need to unescape some HTML characters (if the file name contains e.g. the hash #, this would be returned as %23. We decode this by using the JavaScript function decodeURIComponent()).

Fully featured example

If you not only want to filter the file:/// but also qrc:// and http://, you can use this RegEx:

^(file:\/{3})|(qrc:\/{2})|(http:\/{2})

So the new, complete code would be:

FileDialog {
    onAccepted: {
        var path = myFileDialog.fileUrl.toString();
        // remove prefixed "file:///"
        path= path.replace(/^(file:\/{3})|(qrc:\/{2})|(http:\/{2})/,"");
        // unescape html codes like '%23' for '#'
        cleanPath = decodeURIComponent(path);
        console.log(cleanPath)
    }
}

This is a good playground for RegEx'es: http://regex101.com/r/zC1nD5/1



回答2:

In MS Windows "file:///c:\foo\bar.txt" should be converted to "c:\foo\bar.txt". However in Linux the url "file:///Users/data/abcdef" has the correct path as "/Users/data/abcdef". I have created a simple function to convert url to path:

function urlToPath(urlString) {
    var s
    if (urlString.startsWith("file:///")) {
        var k = urlString.charAt(9) === ':' ? 8 : 7
        s = urlString.substring(k)
    } else {
        s = urlString
    }
    return decodeURIComponent(s);
}


回答3:

Following Chris Dolan's answer above, it's probably neatest to deal with this using a slot in C++:

public slots:

void handleFileChosen(const QString &urlString) {
    const QUrl url(urlString);
    if (url.isLocalFile()) {
        setFile(QDir::toNativeSeparators(url.toLocalFile()));
    } else {
        setFile(urlString);
    }
}