ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入浅出 Qt 文件操作:从 QIODevice 核心体系到 QFile / QFileInfo 实战

深入浅出 Qt 文件操作:从 QIODevice 核心体系到 QFile / QFileInfo 实战 个人主页Cx330❄️个人专栏《C语言》《LeetCode刷题集》《数据结构-初阶》《C知识分享》《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战心向往之行必能Cx330的简介目录前言一、 Qt I/O 抽象基类QIODevice 家族核心派生类介绍二、 QFile 核心 API 详解1. 打开文件open2. 读取文件read / readLine / readAll3. 写入文件write4. 关闭文件close5. 实战示例1文本文件读写简易记事本三、 文本文件与二进制文件的差异实战示例2二进制文件读写适用于图片 / 视频 / 二进制数据四、 文件属性管理QFileInfo五、 总结前言在进行 C/C 编程时文件读写与处理是我们绕不开的核心需求。不同的环境和标准提供了不同的 APIC 语言使用fopen/fread/fwrite/fcloseC 标准库使用fstreamifstream/ofstream、/运算符及closeLinux 系统调用使用open/read/write/close虽然我们在 Qt 中完全可以混用上述原生方案但在实际 Qt 开发中强烈推荐使用 Qt 自带的文件操作体系。为什么一方面Qt 诞生的年代非常早早于 C98 标准化当时 C 尚未形成统一的跨平台标准库另一方面Qt 提供的 API 能与QString、QByteArray等 Qt 核心类型实现完美无缝的配合。本文将基于 Qt 的 I/O 架构全面剖析 Qt 中的文件读写及相关辅助类。一、 Qt I/O 抽象基类QIODevice 家族Qt 中所有的输入/输出I/O设备都继承自QIODevice。它统一了文件、网络、串口、进程间通信等各种设备的操作接口。┌─ QFile ──┬─ QTemporaryFile ┌─ QFileDevice ─┤ └─ QSaveFile │ └─ ... ├─ QAbstractSocket ── (QTcpSocket / QUdpSocket) ├─ QSerialPort QIODevice ─┼─ QBluetoothSocket ├─ QProcess └─ QBuffer核心派生类介绍QFileDevice家族QFile最常用的普通文件读写类。QTemporaryFile临时文件类。特点当该对象销毁时对应的临时文件会自动在磁盘中被删除。QSaveFile安全写入文件类。【设计模式与应用场景】在写入大量数据时如果直接对原文件清空并写入万一写到一半程序崩溃或断电新数据没写完旧数据也丢失了。QSaveFile的策略是先将数据写入一个临时文件中等所有内容都成功写完并提交commit后再自动删除旧文件并替换为新文件。这是一种极为常见的安全写入策略。QAbstractSocket包含QTcpSocket与QUdpSocket用于网络套接字通信。QSerialPort串口通信。在嵌入式开发和单片机/开发板交互中非常常见。QBluetoothSocket蓝牙通信接口。QProcess对底层fork/exec进程创建与交互操作的封装。QBuffer内存缓冲区将内存中的QByteArray当作 I/O 设备来进行读写操作。二、 QFile 核心 API 详解QFile是处理本地文件读写最核心的类。它的基本使用流程符合经典的“打开 ➔ 读/写 ➔ 关闭”范式。1. 打开文件open可以通过构造函数指定文件路径支持相对路径与绝对路径QFile file(test.txt); // 或绝对路径 C:/Users/demo/test.txt调用open()方法指定打开模式bool open(QIODevice::OpenMode mode) override;常见的OpenMode枚举选项枚举值说明QIODevice::ReadOnly只读模式打开QIODevice::WriteOnly只写模式打开QIODevice::ReadWrite读写模式打开 (ReadOnly|WriteOnly)QIODevice::Append追加写入模式QIODevice::Truncate打开时清空原有内容QIODevice::Text文本模式自动转换换行符\r\n↔\nQIODevice::Unbuffered无缓冲模式2. 读取文件read/readLine/readAllQFile提供了多种灵活的读取接口qint64 read(char *data, qint64 maxSize); QByteArray read(qint64 maxSize); QByteArray readAll(); // 一次性读取全部内容 qint64 readLine(char *data, qint64 maxSize); QByteArray readLine(qint64 maxSize 0); // 按行读取小技巧Qt 读出的返回类型通常为QByteArray字节数组可以非常方便地转换为QString例如QString content file.readAll();。3. 写入文件writeqint64 write(const char *data, qint64 maxSize); qint64 write(const char *data); qint64 write(const QByteArray byteArray);4. 关闭文件closevirtual void close();【重点分析为什么必须调用close()】关闭文件本质上是释放操作系统文件描述符表File Descriptor Table中的表项。 操作系统的文件描述符数量是有上限的。如果打开文件后不及时关闭会导致文件描述符泄漏当表被占满后后续所有尝试打开文件的操作都会失败5. 实战示例1文本文件读写简易记事本#include mainwindow.h #include ui_mainwindow.h #include QPlainTextEdit #include QFileDialog MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); // 获取到菜单栏 this-setWindowTitle(简单的记事本); // 获取到菜单栏 QMenuBar* menubar this-menuBar(); // 添加菜单 QMenu* menu new QMenu(文件); menubar-addMenu(menu); // 添加菜单项 QAction* action1 new QAction(打开); QAction* action2 new QAction(保存); menu-addAction(action1); menu-addAction(action2); // 指定一个输入框 edit new QPlainTextEdit(); QFont font; font.setPixelSize(20); edit-setFont(font); this-setCentralWidget(edit); // 连接 QAction 的信号槽 connect(action1, QAction::triggered, this, MainWindow::handle1); connect(action2, QAction::triggered, this, MainWindow::handle2); } MainWindow::~MainWindow() { delete ui; } void MainWindow::handle1() { // 1. 先弹出 打开文件 对话框让用户选择打开哪个文件 QString path QFileDialog::getOpenFileName(this); // 2. 把文件名显示到状态栏里 QStatusBar* statusBar this-statusBar(); statusBar-showMessage(path); // 3. 根据用户选择的路径, 构造一个 QFile 对象并打开文件 QFile file(path); bool ret file.open(QIODevice::ReadOnly); if(!ret){ statusBar-showMessage(path 打开失败); return; } // 4. 读取文件 // 需要确保打开的文件是一个文本文件才可以 // 如果是二进制文件,交给QString就不太合理了 QString text file.readAll(); // 5. 关闭文件(千万不要忘记) file.close(); // 6. 读到的内容设置到输入框中 edit-setPlainText(text); } void MainWindow::handle2() { // 1. 先弹出一个 保存文件 对话框 QString path QFileDialog::getSaveFileName(this); // 2. 在状态栏显示这个文件名 QStatusBar* statusBar this-statusBar(); statusBar-showMessage(path); // 3. 根据用户选择的路径, 构造一个 QFile 对象并打开文件 QFile file(path); bool ret file.open(QFile::WriteOnly); if(!ret){ statusBar-showMessage(path 保存失败); return; } // 4. 写文件 const QString text edit-toPlainText(); file.write(text.toUtf8()); // 5. 关闭文件 file.close(); }三、 文本文件与二进制文件的差异在使用file.readAll()读取内容并赋值给QString时需要注意数据类型的匹配QString text file.readAll();文本文件内容必须是合法的字符编码如 UTF-8、GBK 等。将其读取并直接转为QString进行展示是没有问题的。二进制文件内容为任意字节流如图片、可执行程序.exe、音频、视频等。不能直接交给QString处理否则会因为编码解析失败导致数据损坏或乱码。二进制文件应当使用QByteArray原生字节流进行处理或结合QDataStream序列化。实战示例2二进制文件读写适用于图片 / 视频 / 二进制数据二进制文件图片、视频、exe 等需避免文本模式的行尾符转换下面的这个示例是博主借鉴的哈大家可以看看可以验证下正确性。// 读取二进制文件如图片 void Widget::readBinaryFile() { QString filePath QFileDialog::getOpenFileName(this, 选择图片, ., 图片文件 (*.jpg *.png)); if (filePath.isEmpty()) return; QFile file(filePath); // 二进制只读模式 if (!file.open(QIODevice::ReadOnly)) { QMessageBox::warning(this, 错误, 文件打开失败 file.errorString()); return; } // 读取全部二进制数据 QByteArray imageData file.readAll(); file.close(); // 后续可用于显示图片、网络传输等 QPixmap pixmap; pixmap.loadFromData(imageData); ui-label_image-setPixmap(pixmap.scaled(ui-label_image-size(), Qt::KeepAspectRatio)); } // 写入二进制文件如保存图片 void Widget::writeBinaryFile(const QByteArray data, const QString savePath) { QFile file(savePath); // 二进制只写模式 if (!file.open(QIODevice::WriteOnly)) { QMessageBox::warning(this, 错误, 文件创建失败 file.errorString()); return; } file.write(data); file.close(); QMessageBox::information(this, 成功, 二进制文件保存成功); }关键注意事项必须关闭文件open()后需调用close()释放文件句柄避免资源泄露编码处理文本文件建议用toUtf8()写入避免中文乱码大文件处理避免readAll()一次性加载到内存改用readLine()逐行读取或read(n)分块读取路径处理使用QFileDialog获取路径自动适配跨平台格式避免手动拼接路径出错。四、 文件属性管理QFileInfo除了读写内容我们经常还需要获取文件的元数据如文件大小、创建时间、修改时间、文件权限等。这时就需要用到QFileInfo。在早期的 C/C 标准库中缺乏跨平台获取文件元数据的原生支持往往需要调用特定 OS 的 API如 Windows API 或 POSIXstat。Qt 的解法很早便提供了QFileInfo类方便跨平台获取文件属性。C 标准的跟进直到C17C 标准库才正式引入了filesystem模块来提供类似的功能。QFileInfo常见使用示例QFileInfo info(C:/path/to/file.txt); qint64 size info.size(); // 获取文件大小字节 bool isFile info.isFile(); // 是否为普通文件 bool isDir info.isDir(); // 是否为目录 QDateTime created info.birthTime(); // 获取创建时间 QDateTime lastModified info.lastModified(); // 获取最后修改时间实战示例文件属性获取显示#include mainwindow.h #include ui_mainwindow.h #include QFileDialog #include QDebug #include QFileInfo MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { QString path QFileDialog::getOpenFileName(this); QFileInfo fileInfo(path); qDebug() fileInfo.fileName(); qDebug() fileInfo.suffix(); qDebug() fileInfo.path(); qDebug() fileInfo.size(); qDebug() fileInfo.isFile(); qDebug() fileInfo.isDir(); // ………… }五、 总结统一架构Qt 所有的 I/O 操作都依托于QIODevice基类学会了QFile的接口对于网络 Socket、串口等类的读写逻辑也能快速上手。安全写文件在涉及重要数据持久化时优先考虑使用QSaveFile防止数据意外丢失。资源管理使用完文件务必及时close()避免占用文件描述符。区分类型文本文件用QString/QTextStream二进制文件用QByteArray/QDataStream。属性查询获取文件大小、路径、修改时间等信息时直接使用QFileInfo。
返回列表