c++qtqt5qfileqt-resource

Can not read file with extern type and resource system


I want to read a json file via Qt resource system in a c++ class.

Assume Translator.h:

    class Translator
    {
    public:
        Translator();
    
        void read(const QString &fpath);
        QString valueAt(const QString &key) const;
    
    };
    
    extern Translator _tr;

    inline QString Tr(const QSTring &key) {
        return _tr.valueAt(key);
}

And Translator.cpp:

Translator::Translator() {
    read(":/Resources/Text/Translation.json");
}

void Translator::read(const QString &fpath) {
    QFile f(fpath);
    f.open(QIODevice::ReadOnly | QIODevice::Text);
    f.readAll(); // f.errorString() -> no such file or directory
    f.close();
}

Translator _tr;

And also .qrc file: .qrc:

<RCC version="1.0">
    <qresource>
    <file>Resources/Text/Translation.json</file>
    </qresource>
</RCC>

Every time i run above code i get error :

QIODevice::read (QFile, ":\Resources\Text\Translation.json"): device not open

However when i remove extern Translator object and create that in main function or when replace the path "Resources/Text/Translation.json" with full path there is no more error

Note:

might be good to mention that i want to read Translator.json one time in my whole application and for that i create an extern Translator


Solution

  • In Cannot open resource file, a first solution can be to run qmake again. It is maybe likely to change the link edition with new dependency information.

    Here is a possible explanation. Qt cannot disambiguate ":\Resources\Text\Translation.json" before it reads the content of the .qrc even if the .qrc is compiled in the executable.

    So QFile should need (probably during the step of the initialization of the global variables) an initialization to build an internal map (name -> file).

    If your initialization of Translator _tr; occurs before this map initialization, you have the error. If it occurs after, things should work.

    Another solution could be

    class Translator
    {
    public:
        Translator();
    
        void read(const QString &fpath);
        QString valueAt(const QString &key) const;
    private:
        bool m_ready;
    };
    
    Translator::Translator() : m_ready(false) {}
    
    void Translator::read(const QString &fpath) {
        QFile f(fpath);
        f.open(QIODevice::ReadOnly | QIODevice::Text);
        f.readAll(); // f.errorString() -> no such file or directory
        f.close();
    }
    
    QString Translator::valueAt(const QString &key) const {
        if (!m_ready) {
          m_ready = true;
          read(":/Resources/Text/Translation.json");
        }
        ...
        return ...;
    }