C++Qt文件操作实战:读写流万字全解析!!

#ifndef WIDGET_H
#define WIDGET_H

#include
#include 
#include

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

//signals:
//        void mysignal();
//        void mysignalparams(int value);
//private slots:
//        void myslot();
//        void myslotparams(int value);


private slots:
    void on_btnRead_clicked();

    void on_btnWrite_clicked();

    void on_btnstreamRead_clicked();

    void on_btnstreamWrite_clicked();

    void on_btnQFileDialog_clicked();

    void on_btnSe_clicked();

    void on_btnSave_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
//解释这串代码,写上注释

当然可以!下面是对这段 widget.h 文件的逐行详细中文注释和解释,帮助你理解它的结构、作用以及各个部分的意义。


完整代码 + 中文注释

#ifndef WIDGET_H
#define WIDGET_H
  • 头文件卫士(Header Guard)
    • #ifndef WIDGET_H:如果还没有定义过 WIDGET_H
    • #define WIDGET_H:就定义它;
    • 这样做的目的是防止该头文件被重复包含多次,避免编译错误。
    • 最后以 #endif // WIDGET_H 结束保护。
#include 
  • 引入 C++ 标准输入输出流库,用于如 std::cout 的使用。
#include 
  • 引入 Qt 提供的基础 GUI 类 QWidget,所有自定义窗口部件都继承自这个类。
#include 
  • 引入 Qt 的调试输出工具 qDebug(),比 std::cout 更适合 Qt 程序调试。
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
  • Qt 使用的命名空间宏:
    • namespace Ui { class Widget; } 是对由 .ui 文件生成的 UI 类的前置声明
    • 实际上,在构建项目时,Qt 会根据 .ui 文件自动生成一个名为 ui_widget.h 的文件,里面包含了界面上所有控件的定义;
    • 这里只是提前告诉编译器“这个类存在”,不需要知道具体实现。
class Widget : public QWidget
{
    Q_OBJECT
  • 定义一个名为 Widget 的类,继承自 QWidget
  • Q_OBJECT 是 Qt 的宏,表示这个类支持以下功能:
    • 信号与槽机制(Signal-Slot)
    • 元对象系统(Meta Object)
    • 动态属性、国际化等特性
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
  • 构造函数和析构函数:
    • Widget(QWidget *parent = nullptr):构造函数,默认没有父窗口;
    • ~Widget():析构函数,用于释放资源(如 ui 指针);
//signals:
//        void mysignal();
//        void mysignalparams(int value);
//private slots:
//        void myslot();
//        void myslotparams(int value);
  • 被注释掉的信号和槽函数:
    • mysignal() 和 mysignalparams(int) 是两个自定义信号;
    • myslot() 和 myslotparams(int) 是对应的槽函数;
    • 注释掉意味着当前不启用这些信号/槽,可能是为了测试或暂时不用。
private slots:
    void on_btnRead_clicked();
  • 声明一个私有槽函数:
    • 当界面中名为 btnRead 的按钮点击时自动调用;
    • 函数名格式为 on__(),是 Qt 的自动连接机制要求的命名方式。
    void on_btnWrite_clicked();
  • 当按钮 btnWrite 被点击时触发的槽函数。
    void on_btnstreamRead_clicked();
  • 当按钮 btnstreamRead 被点击时触发的槽函数,通常用于以流方式读取文件。
    void on_btnstreamWrite_clicked();
  • 当按钮 btnstreamWrite 被点击时触发的槽函数,通常用于以流方式写入文件。
    void on_btnQFileDialog_clicked();
  • 当按钮 btnQFileDialog 被点击时触发的槽函数;
  • 预计是用来打开文件选择对话框(QFileDialog),让用户选择要打开或保存的文件。
    void on_btnSe_clicked();
  • 当按钮 btnSe 被点击时触发的槽函数;
  • 名字可能代表“搜索”、“设置”或其他用途,需看 .cpp 文件具体实现。
    void on_btnSave_clicked();
  • 当按钮 btnSave 被点击时触发的槽函数;
  • 通常用于保存数据到文件或数据库。
private:
    Ui::Widget *ui;
  • 私有成员变量:
    • Ui::Widget *ui:指向由 .ui 文件生成的界面类的指针;
    • 通过 ui->xxx 可以访问界面上的所有控件(比如按钮、文本框等);
    • 在构造函数中会调用 ui->setupUi(this); 来初始化界面。
#endif // WIDGET_H
  • 头文件卫士结束标志;
  • 所有在 #ifndef / #define 之间的内容将只被包含一次。

✅ 总结:widget.h 的作用

内容 描述
类定义 class Widget : public QWidget,是一个自定义窗口部件
接口声明 包含构造函数、析构函数、信号、槽函数等声明
自动绑定 支持 Qt 的自动连接机制(如 on_btnXXX_clicked()
UI 访问 通过 ui 指针操作界面上的控件
信号与槽 支持事件驱动编程模型
头文件保护 防止重复包含

小贴士

  • .h 文件负责声明.cpp 文件负责实现
  • 所有以 on_控件名_信号名() 命名的函数都会被 Qt 自动连接;
  • 如果你在 .ui 中添加了新的按钮,记得:
    • 设置好 objectName
    • 在 .h 中声明对应的 private slots: 函数;
    • 在 .cpp 中实现该函数逻辑。

如果你还需要我帮你写出对应的 .cpp 文件实现,或者演示如何配合 .ui 文件工作,也可以继续提问

#include "widget.h"
#include "ui_widget.h"

#include 
#include

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
//    connect(this, SIGNAL(mysignal()), this, SLOT(myslot()));
//    connect(this, SIGNAL(mysignalparams(int)), this, SLOT(myslotparams(int)));
//    emit mysignal();
//    emit mysignalparams(100);
}

Widget::~Widget()
{
    delete ui;
}

//void Widget::myslot()
//{
//    std::cout << "myslot" << std::endl;
//}

//void Widget::myslotparams(int value)
//{
//    qDebug() << "myslotparams";
//    qDebug() << value;
//}


void Widget::on_btnRead_clicked()
{
//    QFile file("E:/QT2/test.txt");
      QFile file;
      file.setFileName("E:/QT/test.txt");
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        qDebug() << "file open error";
    }
    int size = file.size();
    char* context = new char(size);
    char* con = (char *)malloc(sizeof(char)*size);
//    char context[100] = {"\0"};
    if(file.read(context, 100) == -1) return;
    qDebug() << context;
    file.close();
}


void Widget::on_btnWrite_clicked()
{
    QFile file("E:/QT/test2.txt");
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    file.write("Program 45-QFile001 write something to This File 我是测试");
}


void Widget::on_btnstreamRead_clicked()
{
    QFile file;
    file.setFileName("E:/QT/test.txt");
  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
      qDebug() << "file open error";
  }

    QTextStream in(&file);
    in.setCodec("UTF-8");
    //QString context = in.read(file.size());
    while(!in.atEnd()){
    QString context = in.readLine();
    qDebug() << context;
    qDebug() << "---------";
    }

    file.close();
}


void Widget::on_btnstreamWrite_clicked()
{
    QFile file;
    file.setFileName("E:/QT/test3.txt");
  if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
      qDebug() << "file open error";
  }
    QTextStream out(&file);
    out.setCodec("UTF-8");
    out << "I write stream char to file ";
    file.close();
}


void Widget::on_btnQFileDialog_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), "E:/QT/",
        tr(" Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"));
    qDebug() << fileName;

    QFile file;
    file.setFileName(fileName);
  if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
      qDebug() << "file open error";
  }

    QTextStream in(&file);
    in.setCodec("UTF-8");
    //QString context = in.read(file.size());
    while(!in.atEnd()){
    QString context = in.readLine();
    qDebug() << context;
    qDebug() << "---------";
    }

    file.close();
}


void Widget::on_btnSe_clicked()
{
//    int arr[120];
//    for (int i : arr) {

//    }

    QFileDialog qFileDialog;
    qFileDialog.setFileMode(QFileDialog::ExistingFiles);
    qFileDialog.setNameFilter("*.txt");
    qFileDialog.exec();
    QStringList qstrings = qFileDialog.selectedFiles();
    for(QString str : qstrings){
            qDebug() << str;
    }
}


void Widget::on_btnSave_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                               "E:/QT/untitled.txt",
                               tr("Text (*.txt *.doc)"));
    qDebug() << fileName;
    QFile file;
    file.setFileName(fileName);
  if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
      qDebug() << "file open error";
  }
    QTextStream out(&file);
    out.setCodec("UTF-8");
    out << "Qdialog Write Data to the Txt File";
    file.close();
}

这段代码是一个 Qt 程序中 widget.cpp 文件的完整实现,配合你之前提供的 widget.h.ui 文件一起工作,实现了多个与文件操作和对话框交互相关的功能。

下面我将为你逐行添加详细的中文注释,并解释每个函数的作用、逻辑及潜在优化点。


包含头文件

#include "widget.h"
#include "ui_widget.h"         // 自动生成的 UI 类定义(包含界面控件)
#include                // 用于文件读写操作
#include          // 用于弹出文件选择对话框

构造函数和析构函数

// 构造函数:初始化窗口部件
Widget::Widget(QWidget *parent)
    : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);  // 初始化由 .ui 文件生成的界面控件
}
  • 使用了 Qt 的标准初始化方式;
  • ui->setupUi(this) 将界面上的按钮、标签等控件加载到程序中。
// 析构函数:释放资源
Widget::~Widget()
{
    delete ui;  // 删除 UI 对象
}

按钮点击事件处理函数

✅ 1. on_btnRead_clicked() —— 使用字节方式读取文件内容(不推荐)

void Widget::on_btnRead_clicked()
{
    QFile file;
    file.setFileName("E:/QT/test.txt");  // 设置文件路径

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "file open error";  // 打开失败提示
        return;
    }

    int size = file.size();  // 获取文件大小

    char* context = new char(size);  // ❗错误!应为 new char[size]
    char* con = (char *)malloc(sizeof(char)*size);  // 未使用

    if(file.read(context, 100) == -1) {  // 读取最多100个字节
        qDebug() << "read error";
        return;
    }

    qDebug() << context;  // 输出内容到调试控制台

    file.close();

    // ❗必须释放内存
    delete[] context;  // ❗注意:new[] 要用 delete[]
    free(con);
}

问题与建议

  • new char(size) 只分配了一个字符的空间,不是字符串长度;
  • 推荐改用 QByteArray 或 QString 来避免手动管理内存;
  • 建议使用流式读取或 QTextStream 更安全高效。

✅ 2. on_btnWrite_clicked() —— 写入文本文件

void Widget::on_btnWrite_clicked()
{
    QFile file("E:/QT/test2.txt");

    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "file open error";
        return;
    }

    file.write("Program 45-QFile001 write something to This File 我是测试");
    file.close();
}

说明

  • 如果文件不存在会自动创建;
  • 如果已存在则清空内容再写入;
  • 支持中文(Qt 默认 UTF-8);

✅ 3. on_btnstreamRead_clicked() —— 使用 QTextStream 流方式读取文件

void Widget::on_btnstreamRead_clicked()
{
    QFile file;
    file.setFileName("E:/QT/test.txt");

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "file open error";
        return;
    }

    QTextStream in(&file);
    in.setCodec("UTF-8");  // 设置编码格式支持中文

    while(!in.atEnd()) {
        QString context = in.readLine();  // 逐行读取
        qDebug() << context;
        qDebug() << "---------";
    }

    file.close();
}

优点

  • 更适合读取文本文件;
  • 支持中文;
  • 逐行读取效率高。

✅ 4. on_btnstreamWrite_clicked() —— 使用 QTextStream 流方式写入文件

void Widget::on_btnstreamWrite_clicked()
{
    QFile file;
    file.setFileName("E:/QT/test3.txt");

    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "file open error";
        return;
    }

    QTextStream out(&file);
    out.setCodec("UTF-8");  // 设置编码格式

    out << "I write stream char to file ";
    file.close();
}

说明

  • 使用 << 运算符像 std::cout 一样输出内容;
  • 支持多语言(中文);
  • 写入前文件内容会被清空。

✅ 5. on_btnQFileDialog_clicked() —— 弹出文件打开对话框并读取文件内容

void Widget::on_btnQFileDialog_clicked()
{
    // 弹出文件选择对话框
    QString fileName = QFileDialog::getOpenFileName(
        this,
        tr("Open Image"),
        "E:/QT/",
        tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)")
    );

    qDebug() << fileName;

    QFile file;
    file.setFileName(fileName);

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "file open error";
        return;
    }

    QTextStream in(&file);
    in.setCodec("UTF-8");

    while(!in.atEnd()) {
        QString context = in.readLine();
        qDebug() << context;
        qDebug() << "---------";
    }

    file.close();
}

功能

  • 用户可以选择任意文本文件进行读取;
  • 支持多种文件类型过滤;
  • 读取后输出到调试控制台。

✅ 6. on_btnSe_clicked() —— 多文件选择对话框

void Widget::on_btnSe_clicked()
{
    QFileDialog qFileDialog;
    qFileDialog.setFileMode(QFileDialog::ExistingFiles);  // 允许选择多个文件
    qFileDialog.setNameFilter("*.txt");                   // 仅显示 .txt 文件
    qFileDialog.exec();                                   // 显示对话框

    QStringList selectedFiles = qFileDialog.selectedFiles();  // 获取选中文件列表

    for(QString str : selectedFiles){
        qDebug() << str;
    }
}

功能

  • 弹出多选文件对话框;
  • 限制只能选择 .txt 文件;
  • 输出所有选中的文件路径。

✅ 7. on_btnSave_clicked() —— 弹出保存文件对话框并写入内容

void Widget::on_btnSave_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(
        this,
        tr("Save File"),
        "E:/QT/untitled.txt",
        tr("Text (*.txt *.doc)")
    );

    qDebug() << fileName;

    QFile file;
    file.setFileName(fileName);

    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "file open error";
        return;
    }

    QTextStream out(&file);
    out.setCodec("UTF-8");

    out << "Qdialog Write Data to the Txt File";
    file.close();
}

功能

  • 用户可输入文件名并选择保存路径;
  • 自动创建新文件;
  • 写入指定内容。

总结:功能一览表

函数名 功能描述
on_btnRead_clicked() 使用字节方式读取文件内容(不推荐)
on_btnWrite_clicked() 写入固定文本到文件
on_btnstreamRead_clicked() 使用 QTextStream 读取文件内容(推荐)
on_btnstreamWrite_clicked() 使用 QTextStream 写入文件内容(推荐)
on_btnQFileDialog_clicked() 打开文件选择对话框并读取内容
on_btnSe_clicked() 多选文件并输出路径
on_btnSave_clicked() 保存文件对话框并写入数据

✅ 推荐改进点

改进项 建议
避免手动内存分配 使用 QByteArray 或 QString 替代 new char[]
使用相对路径 避免硬编码绝对路径,提升程序可移植性
添加错误提示机制 如弹窗提示“文件打开失败”而不是只输出调试信息
使用 QTextEdit 显示内容 可将读取结果展示在界面上,而非只打印到调试器
使用 QMessageBox 提示用户 提升用户体验

如果你希望我帮你把这些内容显示在界面上(如 QTextEdit)、增加保存状态提示、或者美化界面布局,也可以继续提问

#include "widget.h"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

这段代码是 Qt 项目中的 main.cpp 文件,它是整个应用程序的入口点。它的作用是创建一个 Qt 应用程序对象、显示主窗口,并进入 Qt 的主事件循环,等待用户交互。


完整代码 + 中文注释

#include "widget.h"        // 包含自定义窗口部件类的头文件
#include     // Qt 提供的应用程序管理类

#include "widget.h"

  • 引入你自定义的窗口类 Widget 的声明;
  • 这个类是你在 .ui 文件中设计的界面所对应的 C++ 类。

#include

  • 引入 Qt 提供的 QApplication 类;
  • 每个 Qt GUI 程序都必须有一个 QApplication 对象;
  • 它负责管理应用程序的生命周期、窗口系统集成、事件处理等。
 
  
int main(int argc, char *argv[])
{
  • main() 是 C/C++ 程序的入口函数;
  • argc 和 argv 是命令行参数:
    • argc:表示命令行参数的数量;
    • argv:是一个字符串数组,保存了所有命令行输入的内容;
 
  
    QApplication a(argc, argv);
  • 创建一个 QApplication 对象 a
  • 这是每个 Qt GUI 应用程序必需的初始化步骤;
  • 它会处理一些与平台相关的初始化工作,比如图形驱动、字体加载等;
  • 同时它也接收命令行参数(如 --style 设置样式)。

 
  
    Widget w;
  • 创建一个 Widget 类的对象 w
  • 这就是你的主窗口;
  • 因为你继承的是 QWidget,所以这个窗口是一个基础窗口部件;
  • 如果你使用 Qt Designer 设计了 .ui 文件,这个窗口将显示你在设计器中设计的界面。

 
  
    w.show();
  • 调用 show() 方法,将窗口显示出来;
  • 默认情况下,窗口是隐藏的,需要手动调用 show() 才能看见。

 
  
    return a.exec();
  • 进入 Qt 的主事件循环;
  • exec() 函数会一直运行,直到用户关闭程序;
  • 在这个过程中,Qt 会不断监听并处理各种事件(如鼠标点击、键盘输入、定时器等);
  • 当最后一个窗口被关闭或调用了 QApplication::quit() 时,exec() 返回,程序结束。

✅ 总结流程图:

程序开始
│
├─ 创建 QApplication 对象 (初始化 Qt 环境)
│
├─ 创建主窗口对象 Widget w
│
├─ 显示窗口 w.show()
│
└─ 进入事件循环 a.exec() ───→ 等待用户操作
                             │
                             └── 用户关闭窗口 → 退出循环 → 程序结束

小贴士

技巧 说明
多窗口应用 可以创建多个窗口对象,通过按钮切换显示
设置窗口标题 在 Widget 构造函数中添加 setWindowTitle("我的第一个 Qt 程序");
设置窗口大小 使用 resize(800, 600);
添加图标 使用 setWindowIcon(QIcon(":/icon.png"));
全屏/最大化 使用 showFullScreen() 或 showMaximized()

如果你希望我帮你添加菜单栏、状态栏、布局管理器或者美化界面,也可以继续提问

你可能感兴趣的:(命令模式,c++,开发语言,算法,java,qt,c语言)