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

Writing text file using QFile.



  • Hello,
    I want to write in a text file from a specific position say 80.
    what i have tried is this:
    QFile file("text.txt"); //global declaration

    file.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(&file):

    file.seek(80);
    out << "Write from this location";

    but in my test.txt all the data gets erased or converted into line as follows
    @^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^Write from this location@^@^@^@^@^@^@^@^@^@^@^@

    what is this phenomenon called and how can i write to a text file from specific position as title intell.



  • @vishbynature Hi,

    Actually using QIODevice::WriteOnly will also "truncate" the file which means any previous content is erased.
    From the doc of QIODevice::WriteOnly:

    The device is open for writing. Note that, for file-system subclasses (e.g. QFile), this mode implies Truncate unless combined with ReadOnly, Append or NewOnly.

    So I guess you need to use

    file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
    

    or some similar combination to make it working.



  • @gojir4
    ok, I will try this.



  • @vishbynature
    I'm not sure QIODevice::Append is what you want. That will always append to your file (you can QFile.seek(), but as soon as you write it should ignore that and go to whatever the end is).

    You need to explain what is in the file (how big it is) at the instant you open it. For example, do you mean that if it is > 80 bytes long you want to start at 80? Would you then want it truncated as you start to write at 80, or would you want it to retain length but overwrite starting from 80? Or what?



  • @vishbynature @JonB is right about Append mode. I guess the easiest way to do this is to read the whole file, do the replacement and then write the whole file content.



  • @gojir4

    I guess the easiest way to do this is to read the whole file, do the replacement and then write the whole file content.

    Noooo! :) Or at least not necessarily. I just need to know what the OP actually wants! You can preserve what is there, and seek, by using QIODevice::ReadWrite instead of QIODevice::WriteOnly.


  • Moderators

    @jonb said in Writing text file using QFile.:

    @vishbynature
    I'm not sure QIODevice::Append is what you want. That will always append to your file (you can QFile.seek(), but as soon as you write it should ignore that and go to whatever the end is).

    You need to explain what is in the file (how big it is) at the instant you open it. For example, do you mean that if it is > 80 bytes long you want to start at 80? Would you then want it truncated as you start to write at 80, or would you want it to retain length but overwrite starting from 80? Or what?

    are you sure? I haven't tested/checked it, but I assumed, Append was simply ReadWrite with a seek to the end of the file?



  • @j-hilk
    No, I never check :) But:

    QIODevice::Append 0x0004 The device is opened in append mode so that all data is written to the end of the file.

    That is standard for append in files. Any write auto-seeks to end of file before writing, not just at file open instant. It's how it works at C level etc. I think the OP will want QIODevice::ReadWrite.

    Having said that, I note it's a text file. A lot of people here think they can write stuff into the middle of a text file, and then the later stuff "squeezes down", or some such, which it will not. When we find out what they really want, it ends up being not an update to the file, but a read whole context while writing out new content as they go. That's why OP needs to clarify!


  • Moderators

    @jonb I checked, seems like my assumption was correct:

    bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
    {
        Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
                   "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
        Q_Q(QFSFileEngine);
        this->fh = fh;
        fd = -1;
        // Seek to the end when in Append mode.
        if (openMode & QIODevice::Append) {
            int ret;
            do {
                ret = QT_FSEEK(fh, 0, SEEK_END);
            } while (ret != 0 && errno == EINTR);
            if (ret != 0) {
                q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
                            QSystemError::stdString());
                this->openMode = QIODevice::NotOpen;
                this->fh = nullptr;
                return false;
            }
        }
        return true;
    }
    


  • well that's a lot of information right now !!
    what i am doing is I have stored information about monthly plan of my project in a text file. As soon as project runs i read all info from "test.txt" and display it on screen as per the month selected. About my UI it has a (cb)combobox which has names of months written and as the index of cb changes the info on lineEdits changes. everything ok uptil now. now for a particular month i want to modify the data thats why I wanted file.seek(80)
    , here 80 is position of that data!! and my one month info is around 250 pos
    so at max pos = 3000 for 12 months. I just want to edit data displayed and it should be modified in the right position!



  • @vishbynature said in Writing text file using QFile.:

    I just want to edit data displayed and it should be modified in the right position!

    would a database (just a simple one using SQLite) help you better with handling the storage/update of your data?



  • @j-hilk
    Hi.

    seems like my assumption was correct:

    Sorry, but what assumption was correct? When the file is opened that code seeks to the end. Expected, but never at issue. But that's not all that opening in append mode does/should do. The question is: what happens when subsequently something writes to the file? If opened in append, it should (re-)seek (in case you've moved the write seek point) to end of file every time a write is performed.

    This makes opening a file in append guarantee that access is "non-destructive" --- anything you write will always be at the end, so you cannot overwrite file content when opening for append. Suitable e.g. for a log file. Which would make the OP's attempt to write at byte #80 actually always write at the end if the file is longer than 80 bytes.

    I'm not sure which are good examples to show you. I picked http://www.cplusplus.com/doc/oldtutorial/files/:

    ios::app All output operations are performed at the end of the file, appending the content to the current content of the file. This flag can only be used in streams open for output-only operations.

    Note the "All output operations are performed at the end of the file ...". Not just "initially the pointer is positioned at end of file". The Qt docs do say:

    QIODevice::Append 0x0004 The device is opened in append mode so that all data is written to the end of the file.



  • @vishbynature
    I don't claim to understand what the best way to do whatever you want here is. Maybe @Pablo-J-Rogina's suggestion of a database. The one thing I can tell you is that achieving whatever you are attempting by seeking to byte #80 in a text file and overwriting what is there is not the right approach.

    If you want some solution which involves sticking with text files, it should look something like: open the existing file for read, open a new file for write, read stuff from old and write to new, making whatever modifications you wish as you go along, close both, delete old file, rename new to old. A few more steps than you wanted! Or, if file not too large, read whole file into some memory structure, make your changes there, write whole memory structure back to the file, completely replacing it.