我正在以最常见的方式阅读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
QTextStream
不会逐字节地从基础QIODevice
读取数据,但有一个内部解码缓冲区,既用于避免支付重复虚拟调用的成本,又用于在更大的块上进行编码转换。
这意味着,一旦你开始在QIODevice
上使用它,它可能从它读取的方式比你从QTextStream
读取的更多;这实际上解释了in the documentation:
由于文本流使用缓冲区,因此不应使用超类的实现从流中读取。例如,如果您有
QFile
并使用QFile::readLine()
直接从中读取而不是使用流,则文本流的内部位置将与文件的位置不同步。
通过连续读取和销毁QTextStream
,您总是根据读取缓冲区大小从文件中获取数据,然后丢弃所有未从文本流中读取的数据。
由于@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
在循环内重复构造。