Get the path from a QML url

24,327

Solution 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

Solution 2

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);
    }
}

Solution 3

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);
}
Share:
24,327

Related videos on Youtube

Timmmm
Author by

Timmmm

Updated on July 09, 2022

Comments

  • Timmmm
    Timmmm almost 2 years

    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.

    • folibis
      folibis almost 10 years
      If you want you app will be cross-platform this URL is exactly what you need. According to RFC 3986 URL starts with protocol. In your case it is file://.All Qt components understand it, even worse sometimes you will get an error while passing something like c:/bar.txt. If you still want to get this URL in wrong way you just want to replace the protocol part - theurl.toString().replace("file:///","")
    • Timmmm
      Timmmm almost 10 years
      Yeah I said I don't want to use regex style hacks. I was wondering if there was a method that actually gives me the path data directly (it is stored in the QUrl object). And this isn't to pass to a Qt component.
    • folibis
      folibis almost 10 years
      Btw, for what do you need it?
    • Timmmm
      Timmmm almost 10 years
      Showing the filename to the user.
    • Chris Dolan
      Chris Dolan almost 10 years
      I dug into the Qt source. The QML "url" type seems to be backed by the C++ QUrl class, which has a very nice toLocalFile() method, but that's not a Q_INVOKABLE method, sadly.
    • Roman Plášil
      Roman Plášil almost 7 years
      I think removing file:/// with 3 slashes is necessary for Windows but will break on Unix.
    • bam
      bam over 3 years
      QUrl class has ::toString(QUrl::FormattingOptions options) method. Relevant options here is QUrl::RemoveScheme and QUrl::PreferLocalFile: org.qt-project.qtlocation.5151/qtcore/… Not sure if it exposed to QML.
  • mozzbozz
    mozzbozz over 9 years
    Ermm no, I'm using this code myself and it works. Of course it works for file:/// URLs only (and not file:// - for two or three slashes, use /^(file:\/{2,3})/). Or what do you mean? For reference, see: regex101.com/r/aO1qG4/1
  • Timmmm
    Timmmm over 9 years
    I mean it won't work for other schemes, like qrc:// or http://. I'm not saying it won't work in many cases; just point out that it isn't the same as QUrl::path().
  • mozzbozz
    mozzbozz over 9 years
    I got it. I assumed, you only wanted files from the file dialog. But you are right, you could also input an http://-URL there. I edited my answer appropriately. I hope I did cover all cases now. But yes, of course a QUrl::path()-like function would be ideal.
  • pooya13
    pooya13 about 3 years
    Why are you removing 3 /// and not just 2?
  • mozzbozz
    mozzbozz about 3 years
    @pooya13 it's been a long time ago, so take this with a grain of salt: I think the reason was that file:/// always has 3 slashes while other "protocols" like http:// have 2 slashes. Not even sure why. Maybe the last slash is just part of the filepath, i.e. /home/mozzbozz (the "root"-slash). Maybe platform dependent? Not sure (but unlikely for Qt).
  • pooya13
    pooya13 about 3 years
    @mozzbozz Thanks for your response. Then I think you need to remove only 2 and leave the third as that seems to be the root slash.