当前位置: 首页 > article >正文

Qt 5.14.2 学习记录 —— 이십 QFile和多线程

文章目录

  • 1、QFile
    • 1、打开
    • 2、读写
    • 3、关闭
    • 4、程序
    • 5、其它功能
  • 2、多线程
    • 1、演示
    • 2、锁
  • 3、条件变量和信号量


1、QFile

Qt有自己的一套文件体系,不过Qt也可以使用C++,C,Linux的文件操作。使用Qt的文件体系和Qt自己的一些类型更好配合。

在这里插入图片描述

管理写入读取的就是Qt中的QIODevice类。QProcess相当于是对fork/exec操作进行的封装;QTemporaryFile表示临时文件,用完就销毁,文件也就删除;在写大量数据时,要先创建一个临时文件,将旧文件内容写到临时文件里,写完后再删除旧文件,这就是QSaveFile的操作。

// 这里的name用绝/相对路径
QFile(const QString& name)

// 查看文档来查看打开、读写、关闭文件操作接口

在这里插入图片描述

1、打开

在这里插入图片描述
不过实际用的是这个,它可以直接拿到之前设置的路径
在这里插入图片描述

关于OpenMode

在这里插入图片描述

2、读写

在这里插入图片描述
在这里插入图片描述
QByteArray容易转QString。
在这里插入图片描述

3、关闭

在这里插入图片描述
关闭时就是在释放文件描述符表中的表项,文件描述符表存在上限。

4、程序

// mainwindow.h

#include <QMainWindow>
#include <QPlainTextEdit>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void handle1();
    void handle2();

private:
    Ui::MainWindow *ui;

    QPlainTextEdit* edit;
};

// mainwindow.cpp

#include <QDebug>
#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);

    connect(action1, &QAction::triggered, this, &MainWindow::handle1);
}

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

void MainWindow::handle1()
{
    // 弹出打开文件对话框
    QString path = QFileDialog::getOpenFileName(this);

    // 文件名显示到状态栏
    QStatusBar* statusBar = this->statusBar();
    statusBar->showMessage(path);

    // 通过路径构造QFile对象
    QFile file(path);
    bool ret = file.open(QIODevice::ReadOnly);
    if (!ret)
    {
        statusBar->showMessage(path + " 打开失败!");
        return ;
    }

    // 读取文件
    // 即使返回值是QByteArray, 也可以直接用QString接收
    // 但前提必须不是二进制文件, 是文本文件
    QString text = file.readAll();

    file.close();

    // 读到的内容设置到输入框中
    edit->setPlainText(text);
}

void MainWindow::handle2()
{
    QString path = QFileDialog::getSaveFileName(this);

    QStatusBar* statusBar = this->statusBar();
    statusBar->showMessage(path);

    QFile file(path);
    bool ret = file.open(QFile::WriteOnly);
    if (!ret)
    {
        statusBar->showMessage(path + " 打开失败!");
        return ;
    }

    const QString& text = edit->toPlainText();
    // 转成QByteArray
    file.write(text.toUtf8());

    file.close();
}

5、其它功能

在这里插入图片描述

QFileInfo可以获取到Qt的文件的相关属性。

void Widget::on_pushButton_clicked()
{
    QString path = QFileDialog::getOpenFileName(this);
    QFileInfo fileInfo(path);   // 构造QFileInfo对象
    qDebug() << fileInfo.fileName();
    qDebug() << fileInfo.suffix();
}

2、多线程

和Linux的多线程本质是一样的。Linux有pthread库,C++11有std::thread,Qt也封装了线程库,参考了Java的线程库。

创建线程要创建QThread对象,并创建一个QThread的子类,重写父类的run函数来作为线程的入口函数。

在这里插入图片描述
在这里插入图片描述

start就是调用系统API来创建线程,创建好后自动执行run函数。

1、演示

创建QWidget项目,通过线程完成定时器功能。

在这里插入图片描述

将intValue属性改为10。

创建新的子类

在这里插入图片描述

// thread.h

#include <QWidget>
#include <QThread>

class Thread : public QThread
{
    Q_OBJECT
public:
    Thread();

    void run();

signals:
    void notify();
};

// widget.h

#include <QWidget>
#include "thread.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

    void handle();

private:
    Ui::Widget *ui;

    Thread thread;
};

// thread.cpp

#include "thread.h"

Thread::Thread()
{

}

void Thread::run()
{
    // 由于Qt的线程策略, 不允许多个线程同时修改界面
    // run实现计时效果
    // 每过一秒钟, 通过信号槽通知主线程修改界面
    for(int i = 0; i < 10; ++i)
    {
        sleep(1);
        emit notify();
    }
}

// widget.cpp

#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(&thread, &Thread::notify, this, &Widget::handle);
    thread.start();
}

void Widget::handle()
{
    int value = ui->lcdNumber->intValue();
    --value;
    ui->lcdNumber->display(value);
}

2、锁

Qt的锁是QMutex,lock和unlock方法。

QWidget项目,创建继承QThread的类Thread。

// thread.h

#include <QWidget>
#include <QThread>

class Thread : public QThread
{
    Q_OBJECT
public:
    Thread();

	// 声明
    static int num;

    void run();
};

// thread.cpp

#include "thread.h"

// 定义
int Thread::num = 0;

Thread::Thread()
{

}

void Thread::run()
{
    for(int i = 0; i < 47000; ++i)
    {
        ++num;
    }
}

// widget.cpp

#include <QDebug>
// widget.h中引入thread.h

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    Thread t1;
    Thread t2;
    t1.start();
    t2.start();

    // 线程等待
    // 如果不等待, 那么除了这两个, Widget这个主线程还在并发执行
    // t1t2开始了, 但是Widget不停, 那么很快就执行到了打印, 此时结果肯定不大
    t1.wait();
    t2.wait();

    qDebug() << Thread::num;
}

这样肯定不会打印出47000 * 2的数字。

加锁

// thread.h

#include <QMutex>

public:
    // 声明
    static int num;
    static QMutex mutex;

// thread.cpp

// 定义
int Thread::num = 0;
QMutex Thread::mutex;

void Thread::run()
{
    for(int i = 0; i < 47000; ++i)
    {
        mutex.lock();
        ++num;
        mutex.unlock();
    }
}

Qt中的智能指针是QMutexLocker,C++ 11中则是std::lock_guard。

// thread.cpp

#include "thread.h"
#include <QMutexLocker>

// 定义
int Thread::num = 0;
QMutex Thread::mutex;

void Thread::run()
{
    for(int i = 0; i < 47000; ++i)
    {
        QMutexLocker locker(&mutex);
        ++num;
    }
}

Qt还有别的锁

在这里插入图片描述

3、条件变量和信号量

QWaitCondition条件变量类,有wait,wake,wakeAll方法

例子

QMutex mutex;
QWaitCondition condition;

//在等待线程中
mutex.lock();

//检查条件是否满足, 若不满足则等待
while (!conditionFullfilled()) 
{
	condition.wait(&mutex); //等待条件满足并释放锁
}

//条件满足后继续执行
//...
mutex.unlock();

//在改变条件的线程中
mutex.lock();

//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程
mutex.unlock();

QSemaphore信号量类

QSemaphore semaphore(2); //同时允许两个线程访问共享资源

//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞

//访问共享资源
//...
semaphore.release(); //释放信号量

//在另⼀个线程中进行类似操作

结束。


http://www.kler.cn/a/520611.html

相关文章:

  • 游戏策划的分类
  • 后端面试题分享第一弹(状态码、进程线程、TCPUDP)
  • AJAX RSS Reader:技术解析与应用场景
  • vue3 获取百度天气
  • 基于OpenCV实现的答题卡自动判卷系统
  • Ansible入门学习之基础元素介绍
  • OSCP - Proving Grounds - Press
  • Nginx中部署多个前端项目
  • Springboot集成Swagger和Springdoc详解
  • 【PyTorch】4.张量拼接操作
  • linux 内核学习方向以及职位
  • 论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(四)
  • shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。
  • Go语言入门指南(二): 数据类型
  • JAVA:利用 Content Negotiation 实现多样式响应格式的技术指南
  • 深入解析ncnn::Net类——高效部署神经网络的核心组件
  • 文献阅读 250125-Accurate predictions on small data with a tabular foundation model
  • SQL Server 使用SELECT INTO实现表备份
  • JWT 实战:在 Spring Boot 中的使用
  • 网络模型简介:OSI七层模型与TCP/IP模型
  • Learning Vue 读书笔记 Chapter 2
  • 【React+ts】 react项目中引入bootstrap、ts中的接口
  • JavaScript使用toFixed保留一位小数的踩坑记录:TypeError: xxx.toFixed is not a function
  • vue3中customRef的用法以及使用场景
  • LeetCode题练习与总结:两个字符串的删除操作--583
  • 9.4 GPT Action 开发实践:从设计到实现的实战指南