学习C++、QT---22(QT中QTextStream库读取文件、写入文件的讲解)
每日一言
你只管努力,把结果交给时间,它会给你最好的答案。
QTextStream
使用QTextStream标准库进行文件的输入输出
我们没当使用一个库的时候,或者是一个类的时候我们就去帮助文档这边寻找灵感,这边我们找到这个QTextStream这个库,我们直接找到案例进行观察,那么可以很容易得出思路,现在上代码
在这边我们在open,也就是以什么样的模式打开文件后,根据官方案例我们创建一个QTestStream的对象in,这个in约定俗成的,因为我们是读取操作从文件读取到程序里面,一般命名为in,输出为out
然后我们这个in需要与QFile的 file对象建立联系,所以需要进行in(&file)这样的操作,
我们这个QTextStream有一个方法叫做readline,这个就是一行一行读,为什么呢?
方法 | 优点 | 缺点 |
readLine() | 内存高效,适合大文件逐行处理 | 多次系统调用,处理小文件较慢 |
readAll() | 单次系统调用,适合小文件 | 可能导致内存溢出 |
read(n) | 灵活控制读取长度 | 需要手动处理换行和缓冲区管理 |
但是我们可以通过这个解释看出,readline是重载函数,一个是需要加上参数,一个是不加参数
我们的案例中是没有参数的,那就是把每一行的数据都读出来,没有限制
如果加上了参数,那么就会有限制,加上参数是有好处的比如:
- 功能:读取一行文本,但最多读取 maxlen 个字符。
- 用途:防止读取超长行导致内存溢出,或处理不规范的文本格式。
atEnd()
现在我们来讲一讲这个atEnd()这个函数
这段代码的执行逻辑是:逐行读取文件内容,直到文件结束。让我拆解它的工作流程:
一、代码执行流程
while(!in.atEnd()){ // 检查是否到达文件末尾(初始时未读,返回false)
QString context = in.readLine(); // 读取一行(自动跳过换行符)
qDebug() << context; // 输出当前行内容
} // 循环回到开头,再次检查是否到达文件末尾
详细步骤:
首次进入循环:
- in.atEnd() 返回 false(因为还没开始读)。
- 执行 in.readLine(),读取第一行并移除换行符。
- 打印第一行内容。
后续循环:
- 每次循环结束时,in.atEnd() 检查是否还有数据可读。
- 如果有,继续读取下一行;如果没有(已读完最后一行),atEnd() 返回 true,循环终止。
二、关键点解释
1. atEnd() 的工作机制
- atEnd() 检测的是下一次读取操作是否会失败(而非当前位置)。
- 当读取到文件最后一行后,atEnd() 仍返回 false,直到尝试读取超过文件末尾时,才会返回 true。
2. 最后一行的处理
- 即使最后一行没有换行符,readLine() 也能正确读取整行内容。
- 当读取完最后一行后,atEnd() 在下一次检查时变为 true,循环终止。
三、示例文件演示
假设文件内容为:
第一行
第二行
第三行
执行过程:
- 第一次循环:
- context = "第一行"(读取第一行,atEnd() 为 false)。
- 第二次循环:
- context = "第二行"(读取第二行,atEnd() 为 false)。
- 第三次循环:
- context = "第三行"(读取第三行,atEnd() 为 false)。
- 第四次检查:
- 尝试读取下一行(已无内容),atEnd() 变为 true,循环终止。
四、潜在问题与优化
1. 空文件处理
如果文件为空,循环体不会执行(atEnd() 初始即为 true)。
2. 大文件性能
对于超大型文件(如 GB 级),逐行读取可能较慢。可考虑:
// 一次性读取整个文件(适用于小文件)
QString allText = in.readAll();
QStringList lines = allText.split('\n');
3. 错误处理
建议添加文件打开失败的检查:
运行
QFile file("example.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "文件打开失败:" << file.errorString();
return;
}
五、总结
你的代码实现了安全且高效的逐行读取,适合处理大多数文本文件。核心逻辑是:
atEnd() 保证在尝试读取超过文件末尾时才终止循环,因此能正确处理所有行(包括最后一行)。
TIPS:很多人都搞不懂这个返回值的问题,我这边就举个例子比如我这边的
QString context = in.readLine();
一般都是先打这个出来in.readLine();
我们在打这行代码的时候不可能直接就把返回值也打出来了,因为这个是我们是面向对象啊,那么多的重载函数,那么多的库,怎么可能都记得对应的返回值类型,这个时候我们就可以去翻阅帮助文档或者是鼠标悬停到这个函数上方点一下,就会显示了,那么我们可以看到关于这个函数的返回值类型,或者参数的类型,这样就可以写出来了,但是我们也需要多积累提高开发效率。
好的我们点击运行之后,发现了这个问题,乱码!!!!
怎么解决??
我们这个QTextStream有一个setcodec这个函数
一样的我们找到这个函数,参数就填字符串就好了
一、QTextStream::setCodec(const char *codecName) 的含义
在 QTextStream::setCodec(const char *codecName) 中:
- codecName 是一个C 风格字符串(char* 类型),表示字符编码的名称(如 "UTF-8"、"GBK"、"ISO-8859-1" 等)。
看吧这样就可以了,因为我们记事本上面的编码也是UTF-8,只有编码一样才不会乱码
TIPS:ANSI的编码也可以用GBK解析,自己去大概了解一下就好了
在 Windows 系统中,“ANSI 编码” 通常是指本地系统默认的多字节编码,在简体中文 Windows 系统上,默认情况下就是 GBK 编码 。所以从这个角度讲,在简体中文 Windows 环境下,所谓的 “ANSI 编码” 文件可以用 GBK 解析。
这个就是用QTextSteram去写内容到文件里