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

问题描述 投票:-1回答:2

我正在以最常见的方式阅读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
c++ qt
2个回答
0
投票

QTextStream不会逐字节地从基础QIODevice读取数据,但有一个内部解码缓冲区,既用于避免支付重复虚拟调用的成本,又用于在更大的块上进行编码转换。

这意味着,一旦你开始在QIODevice上使用它,它可能从它读取的方式比你从QTextStream读取的更多;这实际上解释了in the documentation

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

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


0
投票

由于@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
{
   ...
};

然后在使用这些类时,将根据文件类型在适当的子类型中创建FileFormat类。

然后,这些创建的FileFormats将在ReadSingle()WriteSingle()之间的循环中使用,直到其中任何一个返回false。

这将导致出现错误代码,因为QTextStream在循环内重复构造。

© www.soinside.com 2019 - 2024. All rights reserved.