在循环中构造QTextStream会导致文件错误地读取数据

时间:2019-04-03 16:28:57

标签: c++ qt

我以最常见的方式读取QFile,唯一的不同是由于我的程序体系结构,我在读取循环内的文件上初始化了QTextStream

令我惊讶的是,这导致QFile错误地指出了文件位置,并且由于QTextStream这样的结果而导致只读取一行或根据文件而看似随机的行号。

QTextStream为什么会以这种方式表现?我在文档中找不到有关此类问题的任何参考。有什么我想念的吗?

代码示例

这是我正在使用的错误代码(从体系结构中删除并简化了)

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++;
    }
}

输入和输出

给出一个文件,其编号从1到35排成一行,格式如下:

1
2
3
...
35

该算法仅读取一行输出,而预期读取所有行。

输出:

Line 0: 1

预期输出:

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

2 个答案:

答案 0 :(得分:0)

{@ {1}}的重复构造是由于@MatteoItalia回答的原因导致此错误。

固定代码如下:

QTextStream

并产生预期的输出:

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++;
    }
}

其他信息

此错误似乎很明显。诅咒在循环内重复构造对象是一个坏习惯(从性能角度考虑,因为这样的错误),但是在某些体系结构中,这可能并不那么明显。

请考虑以下架构: 名为Line 0: 1 Line 1: 2 Line 2: 3 ... Line 34: 35 的父类具有虚函数,用于读取必须重载的文件的单行,可以使用FileFormat_Parrent来实现。

QTextStream

然后在使用这些类时,将根据文件类型以适当的子类型创建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 { ... }; 类。

然后,将在循环FileFormatReadSingle()之间循环使用这些创建的FileFormat,直到它们之一返回false。

这将导致发生错误代码,因为WriteSingle()是在循环内重复构造的。

答案 1 :(得分:0)

QTextStream不会从基础的QIODevice字节中读取数据,而是具有内部解码的缓冲区,用于避免支付重复的虚拟调用的费用并进行编码更大的转化。

这意味着,一旦您在QIODevice上开始使用它,它从其中读取的内容可能比从QTextStream中读取的内容更多;这实际上是in the documentation的解释:

  

由于文本流使用缓冲区,因此不应使用超类的实现从流中读取数据。例如,如果您有一个QFile并直接使用QFile::readLine()而不是使用流来读取它,则文本流的内部位置将与文件位置不同步。

通过连续读取和销毁QTextStream,您总是会根据读取的缓冲区大小从文件中获取数据,然后丢弃所有未从文本流中读取的内容。