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 usingQFile::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.