045_第三代软件开发-U盘监测

头图

第三代软件开发-U盘监测

文章目录

  • 第三代软件开发-U盘监测
    • 项目介绍
    • U盘监测
      • 原理解释
      • 源代码

关键字: QtQmlUSBDisk文件

项目介绍

欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。

在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。

在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资源消耗,以确保我们的项目在各种平台和设备上都能够高效运行。

无论您是对 QML 和 C++ 开发感兴趣,还是需要我们为您构建复杂的用户界面和后端逻辑,我们都随时准备为您提供支持。请随时联系我们,让我们一同打造现代化、高性能的 QML & C++ 项目!

重要说明☝

☀该专栏在第三代软开发更新完将涨价

U盘监测

一个项目在前期研究阶段需要的是什么,是理论的支撑,在验证这一理论的时候,需要大量的数据做支撑,所以我们需要软件具备数据记录功能,虽然这些功能不会最终暴露给用户,但是在前期研究阶段是必不可少的,所以我们需要具备这个功能,而这个功能开启的必要条件就是第一要在工程模式,第二要在U盘插入的情况下,才会开启。

而最终交付的用户的需求是需要把用户的报告导出到U盘,因为目前咱的设备是不带打印机的,无法直接打印出报告,而Linux下适配打印机,难度会超过Windows,不是我们不会,而是每家用的打印机都不一样,加上技术支持的技术不在线,所以暂时只是支持用户将报告导出到U盘,后期不排除直接配置打印机或者介入医院标准的HIS系统,不过那都是后话了,今天咱们主要解决USB下U盘监测的问题。

闭坑指南

Linux,每种系统实现的方式类似,又不完全一致,所以一下内用仅适用于Ubuntu 22.04版本,其他系统不做保证,不过原理应该是一致的,稍作改动即可。

原理解释

其实不管什么设备,在连入Linux系统,都会对应出一个文件来,为啥内,Linux 设计哲学之一 一切皆文件,所以我们实现的原理就是检测某一个文件夹的变化,这个Qt就给我们提供了很好的类QFileSystemWatcher,可以直接使用就可以。每个系统U盘设备的挂在有一定差异,自行搞一下就OK了。

源代码

头文件


#include <QObject>

#include "T_Core/Turing_FileMonitoring/turing_filesystemwatcher.h"


class XXXX : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool usbIn READ usbIn WRITE setUsbIn NOTIFY usbInChanged)                                    // USB插入标志
    Q_PROPERTY(QString usbPath READ usbPath WRITE setUsbPath NOTIFY usbPathChanged)                         // USB路劲
    Q_PROPERTY(QString systemPath READ systemPath WRITE setSystemPath NOTIFY SystemPathChanged)             // USB监听文件夹

public:
    explicit XXXX(QObject *parent = nullptr);
    ~XXXX();

    static XXXX* getInstance();

    QString getUserName();

    bool usbIn() const;

    void setUsbIn(bool newUsbIn);

    QString usbPath() const;

    void setUsbPath(const QString &newUsbPath);

    const QString &systemPath() const;

    void setSystemPath(const QString &newSystemPath);

signals:
    void usbInChanged();

    void usbPathChanged();

    void SystemPathChanged();

    void signalUmountUSB();


public slots:
    void slotUmountDisk();
private slots:

    void slot_GetSystemDevByName();

    void slot_AddSystemDevByName(QString strFolder, QString strFile);

    void slot_DeleteSystemDevByName(QString strFolder, QString strFile);

private:
    Turing_FileSystemWatcher*                           m_systemWatcher             = nullptr;
    QString                                             m_systemPath                = "";
    QStringList                                         m_systemList;
    bool                                                m_usbIn                     = false;
    QString                                             m_usbPath                   = ".";


};

#endif // XXXX_H

源文件

#include "XXXX.h"

#include <QProcess>

#include <iostream>


#include <QTextStream>
#include <QEventLoop>
#include <QTimer>

#include <QDir>
#include <QEventLoop>
#include <QTimer>

static QTextStream cout(stdout, QIODevice::WriteOnly);


Q_GLOBAL_STATIC(XXXX,XXXX)                                      // 单例宏
/**
 * @brief XXXX::XXXX
 * @param parent
 * 构造函数
 */
XXXX::XXXX(QObject *parent)
    : QObject{parent}
{
    m_systemWatcher = new Turing_FileSystemWatcher();

    connect(m_systemWatcher,&Turing_FileSystemWatcher::signalAddFile,
            this,&XXXX::slot_AddSystemDevByName);
    connect(m_systemWatcher,&Turing_FileSystemWatcher::signalDeleteFile,
            this,&XXXX::slot_DeleteSystemDevByName);

    connect(this, &XXXX::SystemPathChanged,this,
            &XXXX::slot_GetSystemDevByName);

    setSystemPath("/media/" + getUserName());

}

XXXX::~XXXX()
{

}
/**
 * @brief XXXX::getInstance
 * @return
 * 单例接口
 */
XXXX *XXXX::getInstance()
{
    return XXXX;
}
/**
 * @brief XXXX::getUserName
 * @return
 * 获取用户名
 */
QString XXXX::getUserName()
{
#ifdef Q_OS_LINUX
    QStringList envVariables;
    envVariables << "SUDO_USER.*";
    QStringList environment = QProcess::systemEnvironment();
    foreach (QString string, envVariables) {
        int index = environment.indexOf(QRegExp(string));
        if (index != -1)
        {
            QStringList stringList = environment.at(index).split('=');
            if (stringList.size() == 2)
            {
                qInfo() << "系统名称获取成功,系统名称: " << stringList.at(1);
                return stringList.at(1);
            }
        }
    }
    qWarning() << "系统名称获取失败,默认系统名称: " << "turing";
    return "turing";
#endif
}


/**
 * @brief XXXX::slot_GetSystemDevByName 初始化检测U盘是否存在
 */
void XXXX::slot_GetSystemDevByName()
{
    QDir dir(m_systemPath);
    if(!dir.exists())
        return;

    dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::Name);
    m_systemList = dir.entryList();

    if(m_systemList.size() > 0)
    {
        setUsbIn(true);
        // 默认活动U盘为获取的第一个
        setUsbPath(m_systemPath + "/" + m_systemList.at(0));

        qInfo() << "初始化获取U盘,U盘路径: " << m_usbPath;
    }
    else
    {
        setUsbIn(false);
    }
}

/**
 * @brief XXXX::slot_AddSystemDevByName 插入活动U盘
 * @param strFolder
 * @param strFile
 */
void XXXX::slot_AddSystemDevByName(QString strFolder, QString strFile)
{
    if(strFolder != m_systemPath)
        return;

    // 判断是否存在活动U盘
    if(!m_usbIn)
    {
        QEventLoop loop;//定义一个新的事件循环
        QTimer::singleShot(100, &loop, SLOT(quit()));  //创建单次定时器,槽函数为事件循环的退出函数
        loop.exec();  //事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
        setUsbPath(m_systemPath + "/" + strFile);
        setUsbIn(!m_usbIn);
        qInfo() << "挂在U盘,路径: " << m_usbPath;
    }
}

/**
 * @brief XXXX::slot_DeleteSystemDevByName 拔出活动U盘
 * @param strFolder
 * @param strFile
 */
void XXXX::slot_DeleteSystemDevByName(QString strFolder, QString strFile)
{
    if(strFolder != m_systemPath)
        return;

    if(m_usbIn)
    {
        // 判断拔出的是否是活动U盘
        if(m_usbPath != m_systemPath + "/" + strFile)
        {
            return;
        }
        setUsbPath("./");
        setUsbIn(!m_usbIn);

        qInfo() << "U盘非正常状态卸载,请检查数据完整性!";

    }
    else
    {
        qInfo() << "U盘正常弹出. 完毕";
    }
}

/**
 * @brief XXXX::slotUmountDisk  卸载U盘槽函数
 */
void XXXX::slotUmountDisk()
{
    emit signalUmountUSB();

    QEventLoop loop;//定义一个新的事件循环
    QTimer::singleShot(1000, &loop, SLOT(quit()));  //创建单次定时器,槽函数为事件循环的退出函数
    loop.exec();  //事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出



    int ret = system(QString("echo umount '%1'").arg(m_usbPath).toLocal8Bit());
    if(ret == -1)
    {
        qInfo() << "卸载U盘失败";
    }
    else
    {
        setUsbIn(false);
        qInfo() << "弹出U盘";
    }
}

/**
 * @brief XXXX::usbIn
 * @return
 * 返回USB插入拔出状态
 */
bool XXXX::usbIn() const
{
    return m_usbIn;
}
/**
 * @brief XXXX::setUsbIn
 * @param newUsbIn
 * 设置USB插入拔出状态
 */
void XXXX::setUsbIn(bool newUsbIn)
{
    if (m_usbIn == newUsbIn)
        return;

    m_usbIn = newUsbIn;
    emit usbInChanged();
}
/**
 * @brief XXXX::usbPath
 * @return
 * 返回USB设备路径
 */
QString XXXX::usbPath() const
{
    return m_usbPath;
}
/**
 * @brief XXXX::setUsbPath
 * @param newUsbPath
 * 设置USB设备路径
 */
void XXXX::setUsbPath(const QString &newUsbPath)
{
    if (m_usbPath == newUsbPath)
        return;
    m_usbPath = newUsbPath;
    emit usbPathChanged();
}

/**
 * @brief XXXX::systemPath 返回检测U盘存在路径
 * @return
 */
const QString &XXXX::systemPath() const
{
    return m_systemPath;
}

/**
 * @brief XXXX::setSystemPath 设置检测U盘存在路径
 * @param newSystemPath
 */
void XXXX::setSystemPath(const QString &newSystemPath)
{
    if (m_systemPath == newSystemPath)
        return;
    m_systemPath = newSystemPath;
    qInfo() << "新增监控路径:" << m_systemPath;

    m_systemWatcher ->addWatchPath(m_systemPath);

    emit SystemPathChanged();
}

  1. 这里需要注意,我使用了Qt的属性系统,我这里有三个属性,这些属性将在QML中被使用。

    Q_PROPERTY(bool usbIn READ usbIn WRITE setUsbIn NOTIFY usbInChanged)                                    // USB插入标志
    Q_PROPERTY(QString usbPath READ usbPath WRITE setUsbPath NOTIFY usbPathChanged)                         // USB路劲
    Q_PROPERTY(QString systemPath READ systemPath WRITE setSystemPath NOTIFY SystemPathChanged)             // USB监听文件夹
    
  2. 第二部就是需要给这个U盘检测模块设置一个监测地址

    void XXXX::setSystemPath(const QString &newSystemPath)
    {
        if (m_systemPath == newSystemPath)
            return;
        m_systemPath = newSystemPath;
        qInfo() << "新增监控路径:" << m_systemPath;
    
        m_systemWatcher ->addWatchPath(m_systemPath);
    
        emit SystemPathChanged();
    }
    

    这里搭建看了可一个Turing_FileSystemWatcher,暂时这里可以直接把它理解成为一个Qt的文件监视器,只不过Qt的文件监视器只能知道文件夹变化了,而不能准确返回是增加了、减少了还是修改了,我们自己的Turing_FileSystemWatcher可以分类识别到时增加、减少还是修改,仅此而已,不影响代码阅读。

  3. 接着就是Qt 的事件循环,等待Turing_FileSystemWatcher的信号了。这里就不做具体解释了,代码没有太大难度。看下注释应该没有问题。


博客签名2021

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/117427.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode刷题 - SQL - 简单

目录 1. 175组合两个表 左外连接 2. 181. 超过经理收入的员工 3. 182. 查找重复的电子邮箱 4. 196. 删除重复的电子邮箱 5. 197. 上升的温度 日期作差 6. 511. 游戏玩法分析 I 7. 577. 员工奖金 null条件运算 8. 584. 寻找用户推荐人 9. 586. 订单最多的客户 10. 595. 大的国家…

Linux--线程-条件控制实现线程的同步

1.条件变量 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时&#xff0c;允许线程以无竞争的方式等待特定的条件发生。 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量&#xff0c;其他线程在获…

大航海时代Ⅳ 威力加强版套装 HD Version (WinMac)中文免安装版

《大航海时代》系列的人气SRPG《大航海时代IV》以HD的新面貌再次登场&#xff01;本作品以16世纪的欧洲“大航海时代”为舞台&#xff0c;玩家将以探险家、商人、军人等不同身份与全世界形形色色的人们一起上演出跌宕起伏的海洋冒险。游戏中玩家的目的是在不同的海域中掌握霸权…

新技术前沿-2023-应用GPT提问模板写技术文章

参考一份万能的GPT提问模版&#xff01;直接套用&#xff01; 参考用GPT写技术文章是真爽&#xff01; 参考码住这篇 8200 字 ChatGPT 实战指南&#xff01;&#xff01; 1 GPT提问模板 想让GPT回答的内容符合我们所希望的&#xff0c;最最重要的一点就在于我们如何提问。提问…

【C++】一篇文章搞懂auto关键字及其相关用法!

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【Mybatis小白从0到90%精讲】11:Mybatis批量插入 batchInsert

文章目录 前言foreach批量插入前言 在实际开发中,我们经常需要批量插入大量数据到数据库中,而MyBatis也提供了批量插入的支持,可以大大提高插入效率。 今天要分享的是 工作中常用的在Mapper中使用foreach标签批量插入数据的方式,比在Java代码中循环调用Mapper的单条插入性…

SpringBoot整合EasyExcel

springboot整合easyExcel的全流程&#xff0c;跟着做就能出来。对项目没有侵入要求。0侵入&#xff0c;可插拔 依赖 <!--操作Excel依赖--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>…

微信小程序 uCharts的使用方法

一、背景 微信小程序项目需要渲染一个柱状图&#xff0c;使用uCharts组件完成 uCharts官网指引&#x1f449;&#xff1a;uCharts官网 - 秋云uCharts跨平台图表库 二、实现效果 三、具体使用 进入官网查看指南&#xff0c;有两种方式进行使用&#xff1a;分别是原生方式与组…

康耐视深度学习ViDi-Tool菜单介绍

Train 训练该工具中所有标注的图像 Process 处理该工具中所有的图像 Abort 中止当前训练或处理任务 Rename 更改当前工具的名称 Clone 克隆当前所选工具 Import导出当前所选工具 Export导入相对应的工具 Edit Models编辑工具中的模型 Update Parameters更新当前工具参数 工具菜…

专访虚拟人科技:如何利用 3DCAT 实时云渲染打造元宇宙空间

自古以来&#xff0c;人们对理想世界的探索从未停止&#xff0c;而最近元宇宙的热潮加速了这一步伐&#xff0c;带来了许多新的应用。作为元宇宙的关键入口&#xff0c;虚拟现实&#xff08;VR&#xff09;将成为连接虚拟和现实的桥梁。苹果发布的VISION PRO头戴设备将人们对VR…

C#使用随机数模拟英雄联盟S13瑞士轮比赛

瑞士轮赛制的由来 瑞士制&#xff1a;又称积分循环制&#xff0c;最早出现于1895年在瑞士苏黎世举办的国际象棋比赛中&#xff0c;故而得名。其基本原则是避免种子选手一开始就交锋、拼掉&#xff0c;是比较科学合理、用得最多的一种赛制&#xff1b;英语名称为Swiss System。…

多态 多继承的虚表深度剖析 (3)

&#x1f4af; 博客内容&#xff1a;多态 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准C后端工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家&#xff1a;这里是CSD…

【ES专题】ElasticSearch集群架构剖析

目录 前言阅读对象阅读导航前置知识笔记正文一、ES集群架构1.1 为什么要使用ES集群架构1.2 ES集群核心概念1.2.1 节点1.2.1.1 Master Node主节点的功能1.2.1.2 Data Node数据节点的功能1.2.1.3 Master Node主节点选举流程 1.2.2 分片1.3 搭建三节点ES集群1.3.1 ES集群搭建步骤1…

2、k8s 集群安装

1、kubeadm kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具。 这个工具能通过两条指令完成一个 kubernetes 集群的部署&#xff1a; # 创建一个 Master 节点 $ kubeadm init # 将一个 Node 节点加入到当前集群中 $ kubeadm join <Master 节点的 IP 和端口…

mipi DPHY学习记录

DPHY的内容很多,而且细节很多,我会一点一点的进行补充记录,今天要记录的是cdphy的LP-MODE数据传输的过程。 1:HS 和LP mode lane status 和 lane上的电压 HS mode时,差分线上的电压摆幅为200mv,LP mode时,差分线上的电压为1.2v 2:HS mode data Transmission start 在…

北大软微2024推免拟录取名单及分析

拟录取名单 直博生 硕士生 分析 北大软微在2023年的推免中共录取直博生17人&#xff0c;硕士生205人&#xff0c;其中硕士生全为专硕电子信息 当然&#xff0c;从录取结果咱们可以看出来&#xff0c;除了985和强势211&#xff0c;中国地质&#xff08;北京&#xf…

STM32-高级定时器

以STM32F407为例。 高级定时器 高级定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车&#xff08;断路&#xff09;功能&#xff0c;这些功能都是针对工业电机控制方面。 功能框图 16位向上、向下、向上/向下自动重装载计数器。 16位可编程预分频器&#xff0c…

时间序列预测模型实战案例(八)(Informer)BestPaper论文模型Informer代码实战讲解

论文地址->Informer论文地址PDF点击即可阅读 代码地址-> 论文官方代码地址点击即可跳转下载GIthub链接 本文介绍 本篇博客带大家看的是Informer模型进行时间序列预测的实战案例&#xff0c;它是在2019年被提出并在ICLR 2020上被评为Best Paper&#xff0c;可以说Inform…

JAVA应用中线程池设置多少合适?

目录 1、机器配置&#xff1a; 2、核心线程数 3、最大线程数多少合适&#xff1f; 4、理论基础 5、测试验证 一个线程跑满一个核心的利用率 6个线程 12 个线程&#xff1a;所有核的cpu利用率都跑满 有io操作 6、计算公式 7、决定最大线程数的流程&#xff1a; 1、机器…

HCIA数据通信——路由协议

数据通信——网络层&#xff08;OSPF基础特性&#xff09;_咕噜跳的博客-CSDN博客 数据通信——网络层&#xff08;RIP与BGP&#xff09;_咕噜跳的博客-CSDN博客 上述是之前写的理论知识部分&#xff0c;懒得在实验中再次提及了。这次做RIP协议以及OSPF协议。不过RIP协议不常用…