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

Why can't QSettings be written to QTemporaryFile



  • Hi, all
    I want to encrypt the contents of the INI file. My idea is to first write the contents of qsettings to the temporary file, then encrypt the contents of the temporary file, and finally write to the INI file. But I found that writing qsettings to the temporary file failed. Could you help me please?
    Best regards!

    void JCDemoAES::test()
    {
            // Open temp file
            tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
            tmpFile->open();
        
            // Settings
            QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
            settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
            settings.beginGroup("GroupTest");
        
            QStringList list;
            list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
            settings.setValue("UserCode", list);
            settings.setValue("UserCodeDefault", QStringLiteral("1234"));
        
            settings.endGroup();
        
            // Close temp file
            qDebug() << __FUNCTION__ << tmpFile->readAll();
            tmpFile->close();
    }
    


  • Debug output: JCDemoAES::test ""



  • There's no call to QSettings::sync, and the QSettings object isn't destroyed until after attempting to read. The settings may not have been flush to the file yet.

    Waiting until after the sync completes to open the file for reading may also be necessary.



  • @tovax

    Double check what tempFile->fileName() returns and if it really matches your complete file path.

    Can you confirm the creation of such file?



  • @jeremy_k Hi, thank you very much! I modified the code, but I still can't write it successfully.

    Debug output:
    JCDemoAES::test "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.sEbGkR"
    JCDemoAES::test ""

    void JCDemoAES::test()
    {
        // Init temp file
        tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile->open();
        qDebug() << __FUNCTION__ << tmpFile->fileName();
        tmpFile->close();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.sync();
        settings.endGroup();
    
        // Read temp file
        tmpFile->open();
        qDebug() << __FUNCTION__ << tmpFile->readAll();
        tmpFile->close();
    }
    


  • @Pl45m4 Hi, thanks!
    The temporary file has indeed been successfully created. I can see it in the folder.

    Debug output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.LBTGmC"
    JCDemoAES::test 2 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.LBTGmC"
    JCDemoAES::test 3 ""

    void JCDemoAES::test()
    {
        // Init temp file
        tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile->open();
        qDebug() << __FUNCTION__ << 1 << tmpFile->fileName();
        tmpFile->close();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.fileName();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.sync();
        settings.endGroup();
    
        // Read temp file
        tmpFile->open();
        qDebug() << __FUNCTION__ << 3 << tmpFile->readAll();
        tmpFile->close();
    }
    


  • QSettings::sync() should go after QSettings::endGroup().



  • @jeremy_k Thank you for your patience!
    Debug output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.zJpgBl"
    JCDemoAES::test 2 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.zJpgBl"
    JCDemoAES::test 3 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.zJpgBl"
    JCDemoAES::test 4 ""

    void JCDemoAES::test()
    {
        // Init temp file
        tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile->open();
        qDebug() << __FUNCTION__ << 1 << tmpFile->fileName();
        tmpFile->close();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.fileName();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync();
    
        // Read temp file
        tmpFile->open();
        qDebug() << __FUNCTION__ << 3 << tmpFile->fileName();
        qDebug() << __FUNCTION__ << 4 << tmpFile->readAll();
        tmpFile->close();
    }
    


  • @tovax

    There could be an issue because InitFormat may expect an *.ini extension. Your temp file seem to have ini file format, but a random file extension.
    It could be possible that QSettings wont recognize this file. But this is just a guess.
    The read/write access looks good now

    On Unix, NativeFormat and IniFormat mean the
     same thing, except that the file extension
     is different (.conf for NativeFormat, .ini for IniFormat).
    

    (from: https://doc.qt.io/qt-5/qsettings.html#Format-enum)



  • @Pl45m4 I tested QFile, the write failure should not be caused by the extension.

    Debug output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.TBjIps"
    JCDemoAES::test 2 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.TBjIps"
    JCDemoAES::test 3 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.TBjIps"
    JCDemoAES::test 4 "[GroupTest]\nUserCode=0000, 1111, 2222, 3333\nUserCodeDefault=1234\n"

    void JCDemoAES::test()
    {
        // Init temp file
        // tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile = new QFile(QStringLiteral("%1/%2.TBjIps").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile->open(QIODevice::ReadWrite | QIODevice::Text);
        qDebug() << __FUNCTION__ << 1 << tmpFile->fileName();
        tmpFile->close();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.fileName();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync();
    
        // Read temp file
        tmpFile->open(QIODevice::ReadWrite | QIODevice::Text);
        qDebug() << __FUNCTION__ << 3 << tmpFile->fileName();
        qDebug() << __FUNCTION__ << 4 << tmpFile->readAll();
        tmpFile->close();
    }
    


  • @tovax

    Got (actually not me) the solution...

    Try to open the tempFile one time BEFORE you create the QSettings object.
    Then it should work :)

    Here's the MVP :)
    https://stackoverflow.com/a/57471942

    fileName returns an empty string when the file is not open. Which you did in your first try (but wrong sync). In your latest approach, the file is closed when creating the settings.
    It's a QTemporaryFile thing, this is why it worked with QFile even when the file is closed.

    So open before settings and sync after endGroup :)



  • This works for me:

    #include <QCoreApplication>
    #include <QSettings>
    #include <QTemporaryFile>
    #include <QTextCodec>
    #include <QDebug>
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QTemporaryFile tmpFile("/tmp/tmpfile.XXXXXXX");
        tmpFile.open();
        tmpFile.close();
    
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.setValue("UserCode", "test value");
        settings.sync();
        
        QFile reader(tmpFile.fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << "file" << tmpFile.fileName();
        qDebug() << "content" << reader.readAll();
    }
    

    Output:

    21:19:24: Starting /tmp/build-settingsfile-Desktop_Qt_5_15_5_clang_64bit-Debug/settingsfile ...
    file "/tmp/tmpfile.ZlFULTY"
    content "[General]\nUserCode=test value\n"
    


  • The issue seems to be caching in the QIODevice, at least on macOS with Qt 5.15.5.

    #include <QCoreApplication>
    #include <QSettings>
    #include <QTemporaryFile>
    #include <QTextCodec>
    #include <QDebug>
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QTemporaryFile tmpFile("/tmp/tmpfile.XXXXXXX");
        tmpFile.open();
        tmpFile.write("some text");
        tmpFile.seek(0);
        qDebug() << "tmpfile" << tmpFile.readAll();
        tmpFile.close();
    
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.setValue("UserCode", "test value");
        settings.sync();
    
        QFile reader(tmpFile.fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << "file" << tmpFile.fileName() << reader.fileName();
        qDebug() << "content" << reader.readAll();
        tmpFile.open();
        qDebug() << "tmpfile" << tmpFile.readAll();
    }
    

    Output:

    tmpfile "some text"
    file "/tmp/tmpfile.NmlyxbW" "/tmp/tmpfile.NmlyxbW"
    content "[General]\nUserCode=test value\n"
    tmpfile "some text"
    


  • https://doc.qt.io/qt-6/qiodevice.html says:
    Some subclasses, such as QFile and QTcpSocket, are implemented using a memory buffer for intermediate storing of data.

    My guess is that closing and reopening the QTemporaryFile doesn't discard its buffer and fails to notice the underlying file change.



  • @Pl45m4
    Output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.NYWrOp"
    JCDemoAES::test 2 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.NYWrOp"
    JCDemoAES::test 3 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.NYWrOp"
    JCDemoAES::test 4 ""

    void JCDemoAES::test()
    {
        // Init temp file
        tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()), this);
        tmpFile->open();
        qDebug() << __FUNCTION__ << 1 << tmpFile->fileName();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.fileName();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync();
    
        // Read temp file
        qDebug() << __FUNCTION__ << 3 << tmpFile->fileName();
        qDebug() << __FUNCTION__ << 4 << tmpFile->readAll();
        tmpFile->close();
    }
    


  • @jeremy_k
    PC:
    Win10 64bit
    Qt 5.14.2

        QTemporaryFile tmpFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()));
        tmpFile.open();
        tmpFile.close();
    
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.setValue("UserCode", "test value");
        settings.sync();
    
        QFile reader(tmpFile.fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << "file" << tmpFile.fileName();
        qDebug() << "content" << reader.readAll();
    

    Output:
    file "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.IwayTr"
    content ""



  • @jeremy_k said in Why can't QSettings be written to QTemporaryFile:

    e seems to be caching in the QIODev

        QTemporaryFile tmpFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath()).arg(QApplication::applicationName()));
        tmpFile.open();
        tmpFile.write("some text");
        tmpFile.seek(0);
        qDebug() << "tmpfile" << tmpFile.readAll();
        tmpFile.close();
    
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.setValue("UserCode", "test value");
        settings.sync();
    
        QFile reader(tmpFile.fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << "file" << tmpFile.fileName() << reader.fileName();
        qDebug() << "content" << reader.readAll();
        tmpFile.open();
        qDebug() << "tmpfile" << tmpFile.readAll();
    

    Output:
    tmpfile "some text"
    file "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.bveDgi" "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_14_2_MSVC2017_64bit-Debug/debug/JCDemoAES.bveDgi"
    content "some text"
    tmpfile "some text"



  • I tested qt5.15.2 and couldn't work.
    PC: Win10 64-bit
    Compiler: MSVC2019


  • Lifetime Qt Champion

    You should check QSettings::status() and will notice that you get a QSettings::FormatError since you try to load an invalid ini file.

    qDebug() << "Settings status: " <<  settings.status();


  • @Christian-Ehrlicher Hi, thanks.
    It's "QSettings::NoError".
    Output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/JCDemoAES.tSHxeC"
    JCDemoAES::test 2 QSettings::NoError
    JCDemoAES::test file: "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/JCDemoAES.tSHxeC"
    JCDemoAES::test content: ""

        // Init temp file
        QTemporaryFile tmpFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath(), QApplication::applicationName()), this);
        tmpFile.open();
        tmpFile.close();
        qDebug() << __FUNCTION__ << 1 << tmpFile.fileName();
    
        // Settings
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.status();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync();
    
        // Read temp file
        QFile reader(tmpFile.fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << __FUNCTION__ << "file:" << tmpFile.fileName();
        qDebug() << __FUNCTION__ << "content:" << reader.readAll();
    


  • @Christian-Ehrlicher
    QSettings::status() is "AccessError" after settings.sync();
    Output:
    JCDemoAES::test 3 QSettings::AccessError

        settings.endGroup();
        settings.sync();
        qDebug() << __FUNCTION__ << 3 << settings.status();
    


  • I don't know why access error occurred.

    AccessError
    public static final QSettings.Status AccessError

    An access error occurred (e.g. trying to write to a read-only file). 
    

    A QTemporaryFile will always be opened in QIODevice::ReadWrite mode, this allows easy access to the data in the file. This function will return true upon success and will set the fileName() to the unique filename used.



  • Output:
    JCDemoAES::test 1 "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/JCDemoAES.lwKvTB"
    JCDemoAES::test 2 QSettings::NoError
    JCDemoAES::test 3 QSettings::AccessError
    JCDemoAES::test file: "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/JCDemoAES.lwKvTB"
    JCDemoAES::test content: ""

        // Init temp file
        tmpFile = new QTemporaryFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath(), QApplication::applicationName()), this);
        tmpFile->open();
        qDebug() << __FUNCTION__ << 1 << tmpFile->fileName();
    
        // Settings
        QSettings settings(tmpFile->fileName(), QSettings::IniFormat);
        qDebug() << __FUNCTION__ << 2 << settings.status();
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync();
        qDebug() << __FUNCTION__ << 3 << settings.status();
    
        // Read temp file
        QFile reader(tmpFile->fileName());
        reader.open(QIODevice::ReadOnly);
        qDebug() << __FUNCTION__ << "file:" << tmpFile->fileName();
        qDebug() << __FUNCTION__ << "content:" << reader.readAll();
    
        // Close temp file
        tmpFile->close();
    


  • @tovax
    https://doc.qt.io/qt-5/qtemporaryfile.html#details

    Reopening a QTemporaryFile after calling close() is safe. For as long as the QTemporaryFile object itself is not destroyed, the unique temporary file will exist and be kept open internally by QTemporaryFile.

    It is possible that the fact the file is kept open internally interferes with QSettings ability to write to the file. Create or hand QSettings your own filename in the same directory as QTemporaryFile would (QDir::tempPath()) and verify that succeeds.

    Reduce your code to minimum. Remove the setIniCodec(), and get rid of the beginGroup() stuff and the QStringList, just write a single simple value while you test.


  • Lifetime Qt Champion

    You can't open a file twice for read/write as @JonB correctly told you.



  • @tovax
    I suspect you will find there is indeed a problem trying to use a QTemporaryFile for QSettings, for whatever reason. I refer you to https://www.mail-archive.com/interest@qt-project.org/msg32865.html

    I decided to look at writing the settings out to a QTemporaryFile,

    then just reading that data back in as a string, and then let the

    QTemporaryFile go out of scope and clean itself up. But according to the

    following test code, QSettings does not seem to play nicely with QTemporaryFile:

    I suggest you read that thread and look at his code. Read through all the responses (I did not.) I think you will find the final advice is to use your own temporary file instead.


  • Lifetime Qt Champion

    @JonB I don't see why it's needed - all what is needs to be done is written here. Create a QTemporaryFile, open it, close it again, pass filename to QSettings and go ahead.



  • @Christian-Ehrlicher said in Why can't QSettings be written to QTemporaryFile:

    Create a QTemporaryFile, open it, close it again, pass filename to QSettings and go ahead.

    I believe the OP here tried that earlier (his post before last above) but got the same "access error", did he not? See his earlier code above:

        QTemporaryFile tmpFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath(), QApplication::applicationName()), this);
        tmpFile.open();
        tmpFile.close();
    

    And probably that reference tried to. QTemporaryFile::close() does not close the file, reference the docs I quoted earlier, and I looked at the source and all it does it seek(0). Doubtless to do with keeping a handle into it until the QTemporaryFile goes out of scope, whereupon it will be closed and deleted. Hence if the fact that it is kept open (for all I know with exclusive access) is what stops QSettings working cannot be avoided.


  • Lifetime Qt Champion

    @JonB You're right. It can't work since completely closing a QTemporaryFile will delete it (as this is the usecase for this class).
    I also don't see a reason to use a QTemporaryFile here at all.



  • @tovax might have better luck using QTemporaryDir, and then creating a QFile with a known name within.



  • Here is what the docs say:

    Reopening a QTemporaryFile after calling close() is safe. For as long as the QTemporaryFile object itself is not destroyed, the unique temporary file will exist and be kept open internally by QTemporaryFile.

    So, the temporary file is kept open which is why QSettings cannot write to it. In the end, you just need a temporary file name. How about this:

    QString tmpFileName;
    {
        QTemporaryFile tmpFile(QStringLiteral("%1/%2").arg(QApplication::applicationDirPath(), QApplication::applicationName()), this);
        tmpFile.open();
        tmpFileName = tmpFile.fileName();
    }
    ...
    

    Note the curly braces to restrict the scope if of the temporary file (so it will actually be closed). I cringed a little when I saw that you leaked a pointer to the temporary file because you used new, but never deleted it.



  • @SimonSchroeder said in Why can't QSettings be written to QTemporaryFile:

    So, the temporary file is kept open which is why QSettings cannot write to it. In the end, you just need a temporary file name. How about this:

    That is what I quoted/wrote earlier on.

    I do not understand why you think your code will help the OP. It is true that while the QTemporaryFile tmpFile is in scope Qt holds an open handle into it, which seems to stop QSettings writing to it. However I have previously quoted from the docs, maybe you did not notice, https://doc.qt.io/qt-5/qtemporaryfile.html#details

    and the file will subsequently be removed upon destruction of the QTemporaryFile object.

    The whole point is that when it goes out of scope to release the handle it also deletes the file. OP cannot write to file within the scope and the file will not exist any longer out of scope.

    @tovax
    As I sad earlier. Do not use QTemporaryFile here. Use static QString QDir::tempPath() to make your own temporary file and use that instead. It's not hard to make sure you delete that file explicitly when you are done with it.



  • @SimonSchroeder Hi, thank you very much for your reply. I think the tmpFile will be deleted out of the curly braces.



  • @Christian-Ehrlicher @jeremy_k @JonB @Pl45m4 @SimonSchroeder Thank you very much! QTemporaryDir works.
    Output:
    1 "temp dir:" "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/.hsxxlg"
    2 "temp file:" "E:/JCShared/Projects/JCDemo/JCDemoAES/build-JCDemoAES-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/debug/.hsxxlg/JCDemoAES.tmp"
    3 "settings status:" QSettings::NoError
    4 "temp file content:" [GroupTest]
    UserCode=0000, 1111, 2222, 3333
    UserCodeDefault=1234

        // Temp dir
        QTemporaryDir tmpDir(QStringLiteral("%1/").arg(QApplication::applicationDirPath()));
        qDebug() << 1 << QString("temp dir:") << tmpDir.path();
    
        // Temp file
        QFile tmpFile(QStringLiteral("%1/%2.tmp").arg(tmpDir.path(), QApplication::applicationName()), this);
        tmpFile.open(QFile::ReadWrite | QFile::Text | QFile::Truncate);
        tmpFile.close();
        qDebug() << 2 << QString("temp file:") << tmpFile.fileName();
    
        // Settings
        QSettings settings(tmpFile.fileName(), QSettings::IniFormat);
        settings.setIniCodec(QTextCodec::codecForName("UTF-8"));
        settings.beginGroup("GroupTest");
    
        QStringList list;
        list << QStringLiteral("0000") << QStringLiteral("1111") << QStringLiteral("2222") << QStringLiteral("3333");
        settings.setValue("UserCode", list);
        settings.setValue("UserCodeDefault", QStringLiteral("1234"));
    
        settings.endGroup();
        settings.sync(); // very important
        qDebug() << 3 << QString("settings status:") << settings.status();
    
        // Read temp file
        tmpFile.open(QFile::ReadOnly | QFile::Text);
        QByteArray ba = tmpFile.readAll();
        qDebug() << 4 << QString("temp file content:") << ba.data();
        tmpFile.close();
    


  • Reopening a QTemporaryFile after calling close() is safe. For as long as 
    the QTemporaryFile object itself is not destroyed, the unique temporary 
    file will exist and be kept open internally by QTemporaryFile.
    


  • @tovax said in Why can't QSettings be written to QTemporaryFile:

    I think the tmpFile will be deleted out of the curly braces.

    That is correct. But, that doesn't matter because if it is gone, it is not opened by someone else anymore. There is nothing stopping you from reusing that exact file name. There is also a member function in QTemporaryFile to keep the file after your temporary file object is gone.


Log in to reply