加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

技术 | 嵌入式Linux QT开发之如何实现获取磁盘空间大小的应用逻辑

2022/06/06
966
阅读需 3 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

来源 | 嵌入式应用研究院

整理&排版 | 嵌入式应用研究院

在Window系统上,打开我的电脑,我们就能够看见系统的每个磁盘的可用空间以及总空间,如下所示:

在嵌入式Linux与QT界面结合的产品开发中,我们在做产品的文件管理模块通常来说也需要做这样一个功能。那么如何来实现呢?

方法一:(参考QT大神-飞扬青云的磁盘容量空间控件实现)

利用Linux系统天生就已经提供的df命令来获取,例如我们可以带上-h参数,这样就可以获得以人类可读的格式显示输出,如下所示:

基于韦东山imx6ull开发板文件系统

执行df -h以后,我们能发现一定的规律,即是输出是以行为单位输出的,并且,每一行通过空格来进行分隔标识。因此,我们能够借助QT提供的字符串分割方法以及一些简单的逻辑来实现获取其中一行的内容。

QT大佬-飞扬青云在他的磁盘容量控件里就介绍了这种方法,开源仓库:

https://gitee.com/feiyangqingyun/QWidgetDemo?_from=gitee_search

测试解析一行的函数如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"

void MainWindow::Get_Disk(const QString &result, const QString &name)
{
    uint8_t index = 0;
    uint8_t percent = 0;
    QString dev, use, free, all;
    QStringList list = result.split(" ");
    for (int i = 0; i < list.count(); i++)
    {
        QString s = list.at(i).trimmed();
        if (s == "")
            continue;
        index++;
        if (index == 1)
            dev = s;
        else if (index == 2)
            all = s;
        else if (index == 3)
            use = s;
        else if (index == 4)
            free = s;
        else if (index == 5) {
            percent = s.left(s.length() - 1).toInt();
            break;
        }
    }
    if (name.length() > 0)
        dev = name;
    qDebug() << "设备名称:" << dev ;
    qDebug() << "总空间:" << all ;
    qDebug() << "已经使用了多少空间:" << use ;
    qDebug() << "剩余多少空间:" << free ;
    qDebug() << "使用的空间的百分比:" << percent << "%";
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QString str = "/dev/sda4                14.4G      7.4G      7.0G  52% /mnt";
    Get_Disk(str,"/dev/sda4");
}

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

运行结果:

这种方法即不需要去了解实现原理,简单来说就是一个字符串解析的过程。结合QT的QProcess函数或者Linux C提供的popen函数来调用df -h命令来获取磁盘容量信息,然后通过这种方法循环读取每一行,结合自己产品的业务逻辑去获取对应的内容即可。

方法二、直接把df命令的代码搬过来与QT进行结合

基于statfs函数实现,这种方法其实就是df命令的实现原理,statfs可以用于查询文件系统相关的信息。df命令实现如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/statfs.h>
 
static int ok = EXIT_SUCCESS;
//根据挂载的文件的大小来计算
static void printsize(long double n)
{
    char unit = 'K';
    n /= 1024;
    if (n > 1024) {
        n /= 1024;
        unit = 'M';
    }
    if (n > 1024) {
        n /= 1024;
        unit = 'G';
    }
    printf("%-4.1Lf%c", n, unit);
}
 
static void df(char *s, int always) {
    struct statfs st;
    //statfs函数可用来查询文件系统相关的信息。
    if (statfs(s, &st) < 0) {
        fprintf(stderr, "%s: %sn", s, strerror(errno));
        ok = EXIT_FAILURE;
    } else {
        if (st.f_blocks == 0 && !always)
            return;        
        printf("%-20s  ", s);
        printsize((long double)st.f_blocks * (long double)st.f_bsize);
        printf("  ");
        printsize((long double)(st.f_blocks - (long double)st.f_bfree) * st.f_bsize);
        printf("  ");
        printsize((long double)st.f_bfree * (long double)st.f_bsize);
        printf("   %dn", (int) st.f_bsize);
    }
}
 
int df_main(int argc, char *argv[]) {
    printf("Filesystem             Size   Used   Free   Blksizen");
    if (argc == 1) {
        char s[2000];
        //挂载的文件都在/proc/mounts下显示
        FILE *f = fopen("/proc/mounts", "r");
 
        while (fgets(s, 2000, f)) {
            char *c, *e = s;
 
            for (c = s; *c; c++) {
                if (*c == ' ') {
                    e = c + 1;
                    break;
                }
            }
 
            for (c = e; *c; c++) {
                if (*c == ' ') {
                    *c = '';
                    break;
                }
            }
 
            df(e, 0);
        }
 
        fclose(f);
    } else {
        int i;
 
        for (i = 1; i < argc; i++) {
            df(argv[i], 1);
        }
    }
 
    exit(ok);
}

作为多年Ctrl-C and Ctrl-V职场老司机,想要把它融合到自己代码业务逻辑,那岂不是一件相当容易的事情?经过简单的魔改,需求就搞定了:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <sys/vfs.h>
#include <sys/stat.h>
#include <dirent.h>

/*判断目录是否存在*/
bool dirIsExist(const char *file_path)
{
    DIR * mydir = NULL;
    if ((mydir = opendir(file_path)) == NULL)
        return false;
    closedir(mydir);
    return true;
}

/*获取磁盘的可用空间以及总空间*/
int getDiskInfo(const char *path,double * available,double *total)
{
    uint64_t blocksize;
    uint64_t totalsize;
    uint64_t availablesize;
    struct statfs diskInfo;
    if(dirIsExist(path))
        statfs(path, &diskInfo);
    else
        return -1 ;
    // 每个block里包含的字节数
    blocksize = diskInfo.f_bsize;
    // 总的字节数,f_blocks为block的数目
    totalsize = blocksize * diskInfo.f_blocks;
    // 可用空间大小
    availablesize = diskInfo.f_bavail * blocksize;
    *available = availablesize ;
    *total = totalsize ;
    return 0 ;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    char av_unit = 'K';
    char total_unit = 'K';
    double availablesize = 0.00 ;
    double totalsize = 0.00 ;
    getDiskInfo("/mnt",&availablesize,&totalsize); 
    availablesize /= 1024 ;
    if(availablesize > 1024){
        availablesize /= 1024 ;
        av_unit = 'M';
    }
    if(availablesize > 1024){
        availablesize /= 1024 ;
        av_unit = 'G';
    }
    totalsize /= 1024 ;
    if(totalsize > 1024){
        totalsize /= 1024 ;
        total_unit = 'M';
    }
    if(totalsize > 1024){
        totalsize /= 1024 ;
        total_unit = 'G';
    }
    qDebug() <<"availablesize:" <<  QString("%1%2").arg(QString::number(availablesize, 'f', 1)).arg(av_unit) ;
    qDebug() <<"totalsize:" << QString("%1%2").arg(QString::number(totalsize, 'f', 1)).arg(total_unit) ;
}

在Linux下进行交叉编译后,在开发板将这个程序跑起来,运行如下:

大佬的方法简单粗暴,但个人推荐使用方法二来实现逻辑,可操作空间更大一些。下一期,我们结合iwlist以及wpa_cli来实现WIFI扫描、连接、状态查询等需求。

相关推荐

电子产业图谱

本科毕业于华南理工大学,现美国卡罗尔工商管理硕士研究生在读,曾就职于世界名企伟易达、联发科技等,多年嵌入式产品开发经验,在智能玩具、安防产品、平板电脑、手机开发有丰富的实战开发经验,现任深圳市云之手科技有限公司副总经理、研发总工程师。