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

QTemporaryFile - can't open



  • Hi,
    I would like to create Temporary File, save text to it and read it later. That Temporary File has to be ".txt" file ( Windows 10 ). This is my code:

        QTemporaryFile *tmp = new QTemporaryFile;
        tmp->open();
        tmp->setFileName(tmpFile->fileName()+".txt");
        tmp->setAutoRemove(true);
        QProcess * proc = new QProcess;
        proc->start(here is cmdCommand: cmd /c "ipconfig > tmp->fileName()");
    
        QFile file(tmp->fileName());
        qDebug()<<file.open(QIODevice::ReadOnly);
        qDebug()<<file.errorString();
        qDebug()<<file.fileName();
    
        QTextStream ts(&file);
        while(!ts.atEnd())
        {
    
        }
        file.close();
        delete tmpFile;
    

    qDebug says:
    QFile::setFileName: File (C:/Users/myNameUser/AppData/Local/Temp/nameOfMyApp.CfKtTf) is already opened
    false
    "Can't find that file" //( this is my translation to English, I get this text in my language )
    "C:/Users/myNameUser/AppData/Local/Temp/nameOfMyApp.CfKtTf.txt"

    When I open "C:/Users/myNameUser/AppData/Local/Temp/nameOfMyApp.CfKtTf.txt"
    in Windows Explorer everything is ok ( I see the result of ipconfig ).

    So what is the problem?


  • Lifetime Qt Champion

    @qwe3 Why do you call setFileName() after opening the file?
    Also you should rather use https://doc.qt.io/qt-5/qtemporaryfile.html#createNativeFile-1 to get a temp file name you need.



  • @jsulm Hmmm, when I try ( I delete open() and setFileName() ):

        QTemporaryFile *tmp= QTemporaryFile::createNativeFile("xyz.txt");
        tmp->setAutoRemove(true);
        QProcess * proc = new QProcess;
        THE REST
    

    my app is creashed.

    EDIT: Ok, that function don't create QTemporaryFile with given name. I would like to create only temporary File for the moment in C:/Users/myNameUser/AppData/Local/Temp/


  • Lifetime Qt Champion

    @qwe3 said in QTemporaryFile - can't open:

    my app is creashed

    where exactly?



  • @jsulm I don;t have file xyz.txt on my pc


  • Lifetime Qt Champion

    @qwe3 OK, forget about createNativeFile, it's not what you need.
    Just try to call setFileName BEFORE you try to open the file.


  • Lifetime Qt Champion

    @qwe3 But, actually I'm wondering why you want to set the file name? The problem is that such a file could already exist, that's why there is QTemporaryFile - it makes sure a unique temp file is created.



  • @jsulm When I have:

        QTemporaryFile *tmp = new QTemporaryFile;
        tmp->setFileName(tmpFile->fileName()+".txt");
        tmp->open();
        tmp->setAutoRemove(true);
    

    and I check after that the fileName i get only ".txt".

    Can I read from QTextStream when the file is not "txt"?


  • Lifetime Qt Champion

    @qwe3 said in QTemporaryFile - can't open:

    Can I read from QTextStream when the file is not "txt"?

    Of course you can - file name extension does NOT define the file format and QTextStream does not care about any file name extensions. You can name your file what ever you like. You could for example name a JPEG file picture.txt - it would be still a JPEG image.



  • @jsulm When I have:

        QTemporaryFile *tmp = new QTemporaryFile;
        tmp->open();
        tmp->setAutoRemove(true);
    
        QProcess
    
        QFile file(tmp->fileName());
        qInfo()<<file.open(QIODevice::ReadOnly);
        qInfo()<<file.errorString();
        qInfo()<<file.fileName();
        QTextStream ts(&file);
        while(!ts.atEnd())
       {
          QString line = ts.readLine();
          qDebug()<<"text";
       }
    

    and I open that tmp->fileName() in windows explorer by notepad, it is empty. When I setFileName and add ".txt" it is not empty :D

    Debug before while loop says:
    true
    "Unknown error"
    "C:/Users/myUserName/AppData/Local/Temp/myAppName.nkUyod"

    But I still don't see "text". It is in while loop.


  • Lifetime Qt Champion

    @qwe3 said in QTemporaryFile - can't open:

    QFile file(tmp->fileName());

    There is no need for QFile as QTemporaryFile IS QFile.
    Now you simply try to open a file which is already open.
    Remove file and use tmp directly.

    Also atEnd() will probably return true as your temp file is empty.

    And what is this QProcess in your code snippet?



  • @jsulm Now my code is:

        QTemporaryFile *tmp = new QTemporaryFile;
        tmp->open();
        tmp->setAutoRemove(true);
    
        QProcess *proc = new QProcess;
        QString cmdCommand = R"(cmd /c "net use > )"+tmp->fileName()+R"(")";
        proc->start(cmdCommand);
        qDebug()<<tmp->open();
        qDebug()<<tmp->size();
    
        QTextStream ts(tmp);
        while(!ts.atEnd())
        {
    
        }
    

    qDebug says:
    true
    0

    I know that cmdCommand is good - when I add ".txt" to file, and open that file in Windows Explorer I see the result of that command.


  • Lifetime Qt Champion

    @qwe3 Are you aware that you have to wait until the process has finished before you can access the content of the file? You can't just immediately read the file. And I doubt on Windows this will work as the process probably will not be able to write to this file as it is open in your app. You should call close() before proc->start(cmdCommand); and open again when the process finished.
    Either use https://doc.qt.io/qt-5/qprocess.html#waitForFinished or https://doc.qt.io/qt-5/qprocess.html#finished

    "when I add ".txt" to file, and open that file in Windows Explorer I see the result of that command" - it will work same way without adding .txt if you explicetly open that file in a text editor. Again: file extension does NOT influence the format of the data in the file. It only tells Windows explorer what application to use to pen it if you double click on it. If you don't believe me do this: change the file extension of a picture to .txt and double click on it...



  • @jsulm You are right. But...

    I do something like:
    tmp->fileName(), wait 10 seconds, don't delete tmp and open it in windows Explorer - I still see only empty File. Of course my app is still working.

    "net use" is very simple command


  • Lifetime Qt Champion

    @qwe3 said in QTemporaryFile - can't open:

    wait 10 seconds

    How do you wait? Did you close the tmp file before starting the process as I suggested?
    Also, if using QProcess please do proper error handling to see what happens: https://doc.qt.io/qt-5/qprocess.html#errorOccurred
    https://doc.qt.io/qt-5/qprocess.html#readyReadStandardError
    https://doc.qt.io/qt-5/qprocess.html#error
    https://doc.qt.io/qt-5/qprocess.html#exitCode

    You actually do not need a file here at all to get the output of that command as you can use https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput and https://doc.qt.io/qt-5/qprocess.html#readAllStandardOutput

    QProcess proc;
    QString cmdCommand = "cmd";
    QStringList param;
    param << "/c" << "net" << "use";
    proc.start(cmdCommand, param);
    proc.waitForFinished();
    QByteArray output = proc.readAllStandardOutput();
    

    Also, the way you're currently using QProcess is wrong: do not pass command AND parameter in a single string! See the code above for how it should be (and check documentation).



  • @jsulm Of course I know readAllStandardOutput, but I have to write data to file and from file get data to QTextStream.
    Ok, so when I have code something like ( here I don't use temporary File - textFile5 isn't exists - so it's created ):

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        QFile someFile(R"(C:\Users\myUserName\Desktop\textFile5)");
    
        tmpFile = new QTemporaryFile;
        tmpFile->open();
        proc = new QProcess;
        connect(proc, SIGNAL(errorOccurred(QProcess::ProcessError )), this, SLOT(errorOccurredSlot(QProcess::ProcessError)));
        proc->start(R"(cmd /c "net use > )"+someFile.fileName()+R"(")");
        proc->waitForFinished();
    
        qInfo()<<proc->exitCode();
        tmpFile->close();
        qInfo()<<tmpFile->fileName();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::errorOccurredSlot(QProcess::ProcessError error)
    {
        qInfo()<<error;
    }
    
    

    Everything is ok - I open in windows explorer C:\Users\myUserName\Desktop\textFile5 and there is a data and exitCode is 0.

    Now I change my code to:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        QFile someFile(R"(C:\Users\myUserName\Desktop\text5)");
    
        tmpFile = new QTemporaryFile;
        tmpFile->open();
        proc = new QProcess;
        connect(proc, SIGNAL(errorOccurred(QProcess::ProcessError )), this, SLOT(errorOccurredSlot(QProcess::ProcessError)));
        proc->start(R"(cmd /c "net use > )"+tmpFile->fileName()+R"(")");
        proc->waitForFinished();
    
        qInfo()<<proc->exitCode();
        tmpFile->close();
        qInfo()<<tmpFile->fileName();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::errorOccurredSlot(QProcess::ProcessError error)
    {
        qInfo()<<error;
    }
    
    

    I only change one line: proc->start(R"(cmd /c "net use > )"+tmpFile->fileName()+R"(")");

    Now exitCode is 1 ( so it's different ) and temporary file is empty.


  • Lifetime Qt Champion

    @qwe3 said in QTemporaryFile - can't open:

    Now exitCode is 1 ( so it's different )

    That's why I suggested to implement proper error handling...
    And I think this is now third time I write it: close the temp file before starting process!



  • @jsulm Ok, I close temp file before starting process.

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        tmpFile = new QTemporaryFile;
        tmpFile->open();
        proc = new QProcess;
        tmpFile->close();
        connect(proc, SIGNAL(errorOccurred(QProcess::ProcessError )), this, SLOT(errorOccurredSlot(QProcess::ProcessError)));
        connect(proc, SIGNAL(finished(int , QProcess::ExitStatus )), this, SLOT(finishedSlot(int , QProcess::ExitStatus )));
        proc->start(R"(cmd /c "net use > )"+tmpFile->fileName()+R"(")");
        proc->waitForFinished();
    
        qInfo()<<proc->exitCode();
    
        qInfo()<<tmpFile->fileName();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::errorOccurredSlot(QProcess::ProcessError error)
    {
        qInfo()<<"error"<<error;
    }
    
    void MainWindow::finishedSlot(int exitCode, QProcess::ExitStatus exitStatus)
    {
        qInfo()<<"exitCode in Slot"<<exitCode;
        qInfo()<<"exit Status in Slot"<<exitStatus;
    }
    
    

    qInfo says:
    exitCode in Slot 1
    exit Status in Slot QProcess::NormalExit
    1


  • Lifetime Qt Champion

    @qwe3 "but I have to write data to file and from file get data to QTextStream" - you do not need a file to use QTextStream, I still don't understand why you need a file... It would be way easier to get the output from the command without messing up with temp file.

    QProcess proc;
    QString cmdCommand = "cmd";
    QStringList param;
    param << "/c" << "net" << "use";
    proc.start(cmdCommand, param);
    proc.waitForFinished();
    QTextStream stream(proc.readAllStandardOutput());
    

    Does your current code write the file or not?



  • @jsulm Ok, so the problem is that I can't use QProcess. I have to use winApi CreateProcess, which is a little different. And in this CreateProcess the new process will be have shell parent, so this is very strange. I know. That new process will be execute cmdCommand. I know that can be problem with ( waitForFinished, but at this moment is not a problem ). So I can't use readAllStandardOutput. I have to write data to File. This is only way. So now i would like know why this code with QTemporaryFile and QProcess doesn't work. Of course QProcess works when I use it with file which is on the Desktop or will be created.

    I tested CreateProcess from WinApi and it works, but I have to use QTemporaryFile. So I started from QTemporaryFile and QProcess.

    EDIT my last code which is here: there is no data on temporary File.


  • Lifetime Qt Champion

    @qwe3 I'm completely lost now: why do you think you can't use QProcess?
    Did you actually try the code I provided?
    net is writing to stdout as far as I know (maybe stderr, but that you also can read using QProcess), so using readAllStandardOutput() should give you output from net without any files.



  • @jsulm Because my app is with administrator privileges. So when I do something like:
    process->start("cmd /c net use Z: \192.168.24.12\folderName") I mapped disk to administator Files and I don't see it on myComputer. I read about it on other forum. Because cmd will be has admin privileges too. So I have to create Process with no admin privileges. And createProcess from winApi can do something like that.

    Yes, when I use readAllStandardOutput and I don't use temporaryFile everything is ok. But I have to use temporaryFile.

    EDIT and I want to execute "net use", which give me all drivers mapped to my account ( when I execute this cmd command with admin privileges I get all drivers mapped to admin ).



  • @qwe3
    I too am lost, but why do you think a temporary file created in one process with certain privileges/in a certain location will be accessible/writeable by another process with different privileges? (I think that's what you're doing, you have shown various different code.)



  • @JonB I can create file with createProcess and access to it ( for example read ) from my Main App with admin privileges. I check that. But I want only to use temporary File - no file which is on Desktop. I think the information about winapi and createProcess is not important. Now I only would like to create Temporary File, write to it some data using QProcess and qDebug() this data from file. But I don't want use readAllStandardOutput. Why? When I can do this -> write data to file and read it I can do the same with CreateProcess and QTemporaryFile. So please forgot about winapi :)



  • @qwe3
    I never said anything about "winapi". It is you who say something about the sub-process is running with different permissions from the parent process which creates the file, that's all I'm talking about.

    I think also you are running cmd /c something > tempfile. Does it help instead if you try https://doc.qt.io/qt-5/qprocess.html#setStandardOutputFile, so you don't have to do the redirection in the command?

    Finally, instead of using QTemporaryFile, what happens if you (temporarily) try a fixed, non-temporary file path? To eliminate whether question has anything to do with QTemporaryFile.



  • @JonB I would like to don't write any path to File and delete that file when it finished job. QTemporaryFile do exactly what I want - no Path and setAutoRemove.


  • Moderators

    @qwe3 are you sure about the life time of your QTemporaryFile object ? because the file will be deleted when the object ist destroyed. Thats one of THE features QTemporaryFile has

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

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



  • @J-Hilk
    But in my code:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDebug>
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        tmpFile = new QTemporaryFile;
        tmpFile->open();
        proc = new QProcess;
        tmpFile->close();
        connect(proc, SIGNAL(errorOccurred(QProcess::ProcessError )), this, SLOT(errorOccurredSlot(QProcess::ProcessError)));
        connect(proc, SIGNAL(finished(int , QProcess::ExitStatus )), this, SLOT(finishedSlot(int , QProcess::ExitStatus )));
        proc->start(R"(cmd /c "net use > )"+tmpFile->fileName()+R"(")");
        proc->waitForFinished();
    
        qInfo()<<proc->exitCode();
    
        qInfo()<<tmpFile->fileName();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::errorOccurredSlot(QProcess::ProcessError error)
    {
        qInfo()<<"error"<<error;
    }
    
    void MainWindow::finishedSlot(int exitCode, QProcess::ExitStatus exitStatus)
    {
        qInfo()<<"exitCode in Slot"<<exitCode;
        qInfo()<<"exit Status in Slot"<<exitStatus;
    }
    

    I don't destroy temporary File, so I can go to Windows Explorer and open this file. When I open it, it really exists ( when I change one letter there is error "that file not exists" ). But temporary File is empty.


  • Moderators

    @qwe3 And you say with File it works ? Than QTemprorayFile is the wrong approach here.

    if you control both programs, than there are other better options to transfer information between those programs



  • @qwe3 said in QTemporaryFile - can't open:

    @JonB I would like to don't write any path to File and delete that file when it finished job. QTemporaryFile do exactly what I want - no Path and setAutoRemove.

    I know that. I wrote

    what happens if you (temporarily) try
    To eliminate whether question has anything to do with QTemporaryFile.

    When people suggest you try something in order to find out what's going in case it resolves or clarifies a problem, it's usual to give it a try rather than refusing to do so as it's not what you want at the end....



  • @J-Hilk When I change QTemporaryFile to QFile which is on my Desktop - everything is ok.

    @JonB My English is not good, so I don't understand everything what you say. Sorry for that. You say about setStandardOutputFile, but when I check this function I find out that has to QString fileName. This is not good for me. When I change in my code QTemporaryFile to QFile and add path to that File I have an equivalent to setStandardOutputFile. So I look for only temporary files way.


  • Moderators

    @qwe3 said in QTemporaryFile - can't open:

    I don't destroy temporary File, so I can go to Windows Explorer and open this file. When I open it, it really exists ( when I change one letter there is error "that file not exists" ). But temporary File is empty.

    I'm surprised that your file manager lets you open it in the first place, because according to the documentation

    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 read access you have, write access do not have. anyway QTemporaryFile not the class to use here.

    If you insist on some form of QFile usage, use QDir::tempPath() to locate where QTemporaryFile would have stored the file. That way its "not on the desktop" what ever that even means.



  • @J-Hilk I don't know what means "1" when I execute: qInfo()<<proc->exitCode();

    When I use QFile on desktop i get "0", but exitStatus is the same.


  • Moderators

    @qwe3 said in QTemporaryFile - can't open:

    @J-Hilk I don't know what means "1" when I execute: qInfo()<<proc->exitCode();

    When I use QFile on desktop i get "0", but exitStatus is the same.

    1e505e78-d78b-47d8-affe-b1ced4433264-image.png

    Make sure to add the separator after tempPath():

    QString filePathAndName = QDir::tempPath() + "/myfileName.myExtension";



  • @J-Hilk Thank you. But why I get "1" and from exitStatus - NormalExit?


  • Moderators



  • @J-Hilk Thank you.

    Did you try run my code on your pc? Can you read from QTemporaryFile which have result of "net use'?



  • @qwe3
    There are so many potential errors in your code:

    • You are not running command net use, you are running command cmd /c ....

    • Personally I would not rely on/be sure of what code cmd might exit with. I certainly would not read anything into 1 implying "crashed".

    • You do not attempt to put slots on https://doc.qt.io/qt-5/qprocess.html#started, nor https://doc.qt.io/qt-5/qprocess.html#stateChanged, so I don't even know whether you know whether your process starts or not.

    • You are using waitForFinished(), which is not a good idea, and I believe is stated somewhere should not be used under Windows.

    • You do not attempt to quote the temporary filename/path you are passing to cmd with the redirection. If it contains a space, your code will be wrong.

    • You pass the path as a path from Qt, which uses /, and assume that is acceptable to cmd for redirection. I have written about this before, and pointed out the pitfalls. If you intend to pass a Qt path on the command line to something under Windows, you should make the effort to call https://doc.qt.io/qt-5/qdir.html#toNativeSeparators, at least in my opinion.

    • As I said earlier, if you really think QTemporaryFile is what is causing your problem because it works OK with a file you create instead, why don't you do that instead of insisting on QTemporaryFile? @J-Hilk also suggested this earlier. There is nothing magic in QTemporaryFile.

    I would like to don't write any path to File and delete that file when it finished job.

    I have no idea what you intend by "I would like to don't write any path to File ". If you do not pass a full path to the file to your command, you are asking for trouble. You can delete a file when you're done.


Log in to reply