如何跳过 QFile 的 N 行而不将它们临时存储在 QStrings 中?

Posted

技术标签:

【中文标题】如何跳过 QFile 的 N 行而不将它们临时存储在 QStrings 中?【英文标题】:How can I skip N lines of a QFile without temporarily storing them in QStrings? 【发布时间】:2019-05-19 12:27:13 【问题描述】:

基本上,如果我调用QFile::readLineQFile 的整行将被复制并粘贴到char*QByteArray 中。如果我想跳过 999 行直接进入感兴趣的行(第 1000 行),那么我将无缘无故地复制和粘贴前 999 行,而我只想跳过它们。

我知道istream::ignore 允许用户跳过任意数量的字符,直到找到分隔符,所以

std::ifstream file("file.txt");

for (auto i = 0u; i < 999u; ++i)
    file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

std::string str;
getline(file, str); // The 1,000th line is copied & pasted into str

会让您直接进入第 1000 行,而不会浪费任何时间进行复制和粘贴。我怎样才能用QFile 做同样的事情?

【问题讨论】:

你可以循环调用getChar,直到你看到999个换行符。 【参考方案1】:

Qt 没有用于在不输出读取数据的情况下查找文件到特定字节的下一次出现的 API。

不过,您可以非常接近:

QFileQIODevice::readLine(char *data, qint64 maxSize),它读入一个预分配的缓冲区,可以这样使用:

QFile f("..."); f.open(...);

int maxSize = 1024; // guess that 1kb will be enough per line
QByteArray lineData(maxSize, '\0');
int skipLines = 100;
while(f.readLine(lineData.data(), maxSize) > 0 && skipLines > 0) 
    --skipLines;

readLine() 的这个调用重用了预分配的缓冲区。

您可以看到这里的关键部分是猜测哪个预分配大小是最好的。如果您的行长于猜测的大小,您将跳过不到 100 行,因为每行较长的行需要多次读取。

QTextStream 使用 16kb 的内部缓冲区大小:

来自 qtextstream.cpp:

static const int QTEXTSTREAM_BUFFERSIZE = 16384;

QIODevice 使用相同的缓冲区大小:

来自 qiodevice_p.h:

#define QIODEVICE_BUFFERSIZE Q_INT64_C(16384)

旁注:

QTextStream 也有readLineInto(QString *line, qint64 maxlen = 0),如果maxlen 为0 或读取行的长度为line->capacity(),则动态重新分配line。但是,由于编码的原因,读入QString 总是比读入QByteArray 慢。

不过,QByteArray 不存在像 readLineInto(...) 这样的函数。


使用QIODevice::getChar(char *c)(在 OP cmets 中提出)的解决方案也很合适,因为它使用与readLine 相同的内部读取缓冲区,每次调用都有一点开销,但调用者不必担心超过所选缓冲区大小的行。

【讨论】:

以上是关于如何跳过 QFile 的 N 行而不将它们临时存储在 QStrings 中?的主要内容,如果未能解决你的问题,请参考以下文章

如何流式传输从 FTP 获取的文件而不将其存储在本地?

如何使用相同的外键更新行而不更新它们

如何直接保存到持久存储,而不将数据保存到内存中

在内存中创建 eml 文件而不将其保存在磁盘上

ASP.NET - 如何在浏览器中显示图像而不将图像保存在临时文件中?

Java 如何在 dynamodb 中存储 JSON 对象或 JSON 数组而不将其转换为字符串?