简体   繁体   中英

Constructing QTextStream in a loop causes file to incorrectly read data

I am reading a QFile in the most common way the only difference being due to to my programs architecture I initialized QTextStream on a file inside the reading loop.

To my surprise this has lead to the QFile incorrectly telling the file position and as a result of such the QTextStream is reading just one line or stopping at seemingly random line number depending on the file.

Why does QTextStream behave in this way? I could not find any reference in the documentation about this sort of issue. Is there something I have missed?

Code Example

This is the error code I was using (cut out from the architecture and simplified)

QFile file;
QString line;
int interationCount = 0;
file.setFileName(fileName);

if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{
    while(true)
    {
        QTextStream stream(&file);
        if(stream.readLineInto(&line) == false)
            break; //Or return

        std::count << "Line "<< interationCount << ": " << line << "\n";
        interationCount++;
    }
}

Input and output

Given a file of numbers raging from 1 to 35 ordered on each line in a text format like so:

1
2
3
...
35

The algorithm reads just a single line of output while reading all of the lines is expected.

Output:

Line 0: 1

Expected output:

Line 0: 1
Line 1: 2
Line 2: 3
...
Line 34: 35

Repeated constructing of QTextStream due to reasons answered by @MatteoItalia causes this error.

The fixed code looks like this:

QFile file;
QString line;
int interationCount = 0;

file.setFileName(fileName);

if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{
    QTextStream stream(&file);
    while(stream.readLineInto(&line))
    {
        std::count << "Line "<< interationCount << ": " << line << "\n";
        interationCount++;
    }
}

And produces the expected output:

Line 0: 1
Line 1: 2
Line 2: 3
...
Line 34: 35

Additional Info

This error might seem obvious. Of curse repeatedly constructing object inside a loop is a bad practice (both performance wise and because errors like this), but in certain architectures this might not be as obvious.

Consider the following architecture: parent class called FileFormat_Parrent with virtual functions for reading single line of a file that must be overloaded, which could be using a QTextStream to do so.

class FileFormat_Parrent
{
   public:
       QFile File;
       void* Buffer

   virtual bool ReadSingle() = 0;
   virtual bool WriteSingle() = 0;
};

class FileFormat_Txt : public FileFormat_Parrent
{
   virtual bool ReadSingle() {/*Possibly using QTextStream to do so*/}
   virtual bool WriteSingle() {...}
};

class FileFormat_BinArray : public FileFormat_Parrent
{
   ...
};

Then while using these classes a FileFormat class would be created in the appropriate child type based on the file type.

These created FileFormats would then be used in a loop iterating between ReadSingle() and WriteSingle() until either one of them returns false.

This would result in the error code occurring, because the QTextStream is repeatedly constructed inside the loop.

QTextStream doesn't read data from the underlying QIODevice byte by byte, but has an internal decoded buffer, used both to avoid paying the cost of the repeated virtual call, and to do the encoding conversion on bigger chunks.

This means that, once you start using it on a QIODevice , it may have read from it way more than you read from the QTextStream ; this is actually explained in the documentation :

Since the text stream uses a buffer, you should not read from the stream using the implementation of a superclass. For instance, if you have a QFile and read from it directly using QFile::readLine() instead of using the stream, the text stream's internal position will be out of sync with the file's position.

By continuously reading and destroying the QTextStream you are always getting data from the file according to the read buffer size, and then discarding all that you didn't read from the text stream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM