Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Open text file from ressources multiple times



  • Hey everyone!

    I just wrote a small code generator for a recent project, that generates Arduino code from a Template for certain hardware configurations. The function works fine, if I call it for the first time. Any further call during execution results in an empty template file, which is a simple text file in the ressources whitch does not change at all.

    Here is the code:
    Constructor:
    @CodeMerger::CodeMerger(QObject *parent, int moduleCount) : QObject(parent)
    {
    m_moduleCount = moduleCount;

    moduleFiles = new QList<QFile*>;
    QDir().mkdir("foo");
    m_fooFile = new QFile&#40;"foo/foo.ino"&#41;;
    fooTemplate = new QFile(":/data/template.ino"&#41;;
    
    for(int i=0; i<m_moduleCount; i++&#41;
    {
        QFile *file = new QFile&#40;"foo/module"+QString::number(i&#41;+".h");
        file->open(QFile::ReadWrite | QFile::Truncate);
        moduleFiles->append(file);
        file->close();
    }
    

    }
    @
    Generator:
    @bool CodeMerger::merge(QList<fooModule *> configList)
    {
    // valid config list?
    if(configList.size() != m_moduleCount)
    {
    m_errorMsg = tr("Invalid module config list.");
    return false;
    }

    if(!fooTemplate->open(QFile::ReadOnly | QFile::Text) || !fooTemplate->size())
    {
        m_errorMsg = tr("Template error");
        qDebug() << fooTemplate->size();
    
       // !! HERE IS THE ERROR:
       // every further call of this function reaults in fooTemplate->size() beeing 0, but I don't change the source file anywhere!
    
        fooTemplate->close();
        return false;
    }
    if(!m_fooFile->open(QFile::ReadWrite | QFile::Text | QFile::Truncate))
    {
        m_errorMsg = tr("foo master file error.");
        fooTemplate->close();
        return false;
    }
    
    // copy template to master file
    QByteArray masterBuffer(fooTemplate->readAll());
    fooTemplate->close();
    
    // module file content creation loop
    for(int i=0; i<m_moduleCount; i++)
    {
        QFile *file = moduleFiles->at(i);
    
        if(!file->open(QFile::ReadWrite | QFile::Text | QFile::Truncate))
        {
            m_errorMsg = file->errorString();
            m_fooFile->close();
            return false;
        }
    
        if(configList.at(i))
        {
            // create module file content
            QByteArray moduleCodeBuffer;
            moduleCodeBuffer.append(configList.at(i)->code());
            moduleCodeBuffer.replace("write(", "::foo.write("+QString::number(i).toLocal8Bit()+", ");
    
            // write module code file
            if(file->write(moduleCodeBuffer) == -1)
            {
                m_errorMsg = file->errorString();
                file->close();
                m_fooFile->close();
                return false;
            }
    
            // enable module in master file
            int posS = masterBuffer.indexOf("//connector"+QString::number(i)+"::setup();");
            masterBuffer.remove(posS, 2);
            int posL = masterBuffer.indexOf("//connector"+QString::number(i)+"::loop();");
            masterBuffer.remove(posL, 2);
        }
    
        file->close();
    }
    
    if(m_fooFile->write(masterBuffer) == -1)
    {
        m_errorMsg = m_fooFile->errorString();
        m_fooFile->close();
        return false;
    }
    
    m_fooFile->close();
    
    return true;
    

    }
    @

    Has anybody an idea what might be wrong?

    Thank you very much!


  • Lifetime Qt Champion

    Hi,

    It's a surprising behavior. However since you are reusing the same template again and again, you could read it in a QByteArray and reuse it or just call seek(0) rather than re-open the file each time.

    Hope it helps


  • Moderators

    Keeping the template in memory (QByteArray) like SGaist said would be faster and solve the problem.

    Along the lines of the actual problem though, I notice that QFile has some weird behavior to it if you try to reuse them.

    You can try doing fooTemplate->reset() before you use it again, or better yet I prefer just to create the QFile as I need it. There is no reason to "new" it in your constructor and then continually try to close/reopen it. It is just as easy to do:

    @
    QFile fooTemplate("myfile");
    if (!fooTemplate.open(...))
    xxx;

    // as it is to do:

    Cons::Cons()
    {
    fooTemplate = new QFile("myfile");
    }

    Cons::MyFunc()
    {
    if (!fooTemplate->open(...))
    xxx;
    }
    @

    Doing the former will always have a working file and you don't have to worry about the idiosyncrasy of QFile.

    The best solution is definitely to save it in a buffer and only read it once though. It will be faster (RAM vs Disk access) and solve the problem as well.


Log in to reply