文件IO操作开发笔记(一):使用Qt的QFile对磁盘文件存储进行性能测试以及测试工具

60 篇文章 51 订阅
56 篇文章 15 订阅

文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/128438303

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…(点击传送门)

其他(编程相关)

上一篇:没有了
下一篇:《文件IO操作开发笔记(二):使用Cpp的ofstream对磁盘文件存储进行性能测试以及测试工具


前言

  在做到个别项目对日志要求较高,要求并行写入的数据较多,尽管写入数据的线程放在子线程,仍然会造成界面程序的假死(实际上Qt还是在跑,只是磁盘消耗超过瓶颈,造成假死(注意:控制台还能看到打印输出,linux则能看到打印输出)。
  本篇开发了测试工具,并且测试了QFile在USB3.0和M.2SSD上的写入性能。


补充

  在海思Hi3559AV100,Hi3516DV300以及海思的开发过程中,也发现Qt会假死,后台仍然在继续打印,海思板上的Qt界面假死的原因并不是因为磁盘性能问题,可以解决但涉及到一些关键技术了,此处不提。


第一版本测试v1.0.0

  日志的操作,多半写入都是几十上百字节一条,特殊的项目要求写入不同的文件,分类保存,于是产出了第一版本的,用于测试Qt的。
  在这里插入图片描述

测试工具v1.0.0下载地址

  CSDN粉丝0积分下载地址:https://download.csdn.net/download/qq21497936/87360595


关于对于“文件打开次数属性”的忽略

  理论上也可以忽略,测试跟理论结果一致,因为本身程序的文件打开次数,是新建一个然后写入操作完成后关闭,然后另外新建一个继续重复操作,是流水线排序的,所以这个对单线程写入影响不大。

  因为测试是获取了系统时间,次数少了测不出,次数多了越来越小,偶尔增大,所以可以判断,主要影响时间的还是QDateTime获取时间,然后计算的过程。

  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  选取1000次作为标准,测试文件打开次数的影响:

  在这里插入图片描述

  在这里插入图片描述
  打开次数基本无影响,但是一次测试可以利用这个来一次性测多次每个文件单独写入的耗时。


使用QFile测试结果

  在这里插入图片描述

  在这里插入图片描述

  太小了看不出:
  在这里插入图片描述

  修改程序至v1.0.1版本,只看最终结果(为了模拟日志多线程写入不同文件),下面开始测试。

USB3.0移动硬盘测试结果

  在这里插入图片描述

   在这里插入图片描述

  所以,线程越开越多,在某一个阈值线程数(实际打开操作的文件数)会导致性能大幅下降,而且会持续有多个阈值类似的。

M.2主板上SSD测试结果

  在这里插入图片描述

  在这里插入图片描述


使用QFile(每次写后用flush)测试结果

USB3.0移动硬盘测试结果

  在这里插入图片描述

  在这里插入图片描述

M.2主板上SSD测试结果

  在这里插入图片描述

  在这里插入图片描述

  结论:这个明显收到硬盘数据传输的影响。


关键源码

void FileIoTestManager::slot_optFileUseQtQFile(int loopTime, int loopWrite, int dataSize, bool flush)
{
    QDir dir;
    QString dirPath = QString("%1/%2")
                            .arg(QApplication::applicationDirPath())
                            .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh_mm_ss_zzz"));
    if(dir.mkpath(dirPath))
    {
        message(QString("创建文件夹成功: %1").arg(dirPath));
    }else{
        message(QString("创建文件夹失败: %1").arg(dirPath));
    }

    // 生成数据
    message(QString("生成测试数据,数据长度: %1").arg(dataSize));
    QByteArray byteArray;
    byteArray.append(dataSize, 0xFF);

    message(QString("==========================测试开始=============================="));

    double totalTime = 0;           // 总计时间
    double fileTotalTime = 0;       // 操作单个文件总时间
    double writeFileTime = 0;       // 单个文件单词写入时间

    totalTime = QDateTime::currentDateTime().toMSecsSinceEpoch() * 1.0f;

    for(int loopIndex = 0; loopIndex < loopTime; loopIndex++)
    {
        QString filePath = QString("%1/%2_%3")
                .arg(dirPath)
                .arg(QDateTime::currentDateTime().toString("hh_mm_ss_zzz"))
                .arg(loopIndex, 6, 10, QChar('0'));
        QFile file(filePath);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
        {
            message(QString(" 第%1次创建文件失败").arg(loopIndex + 1));
            continue;
        }
        writeFileTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
        for(int writeIndex = 0; writeIndex < loopWrite; writeIndex++)
        {
//            message(QString("  第%1次写入文件,写入长度%2字节").arg(writeIndex + 1).arg(dataSize));
            int size = 0;
            while(size < byteArray.size())
            {
                int len = file.write(byteArray.mid(size));
                if(len < 0)
                {
                    message(QString("  第%1次写入文件,写入失败").arg(writeIndex + 1));
                    message(QString("==========================测试失败=============================="));
                    break;
                }
//                message(QString("  第%1次写入文件,写入成功").arg(writeIndex + 1));
                if(flush)
                {
                    file.flush();
                }
                size += len;

                if(_stop)
                {
                    file.close();
                    message(QString("==========================测试手动停止==========================="));
                    _stop = false;
                    emit signal_finished();
                    return;
                }
            }
            if(_stop)
            {
                file.close();
                message(QString("==========================测试手动停止==========================="));
                _stop = false;
                emit signal_finished();
                return;
            }
        }
        writeFileTime = QDateTime::currentDateTime().toMSecsSinceEpoch() - writeFileTime;
        writeFileTime = writeFileTime / loopWrite;
        message(QString("每次写入数据平均耗时(不包含打开关闭文件): %1ms").arg(writeFileTime));
//        message(QString(" 第%1次关闭文件").arg(loopIndex + 1));
        file.close();
    }

    message(QString("==========================测试结果=============================="));

    totalTime = QDateTime::currentDateTime().toMSecsSinceEpoch() - totalTime;
    fileTotalTime = totalTime * 1.0f / loopTime;
    message(QString("操作创建文件次数: %1, 单个文件循环写入次数: %2, 每次写入固定数据长度: %3, %4")
            .arg(loopTime)
            .arg(loopWrite)
            .arg(dataSize)
            .arg(flush ? "每次使用flush" : "不使用flush"));
    message(QString("总耗时: %1ms").arg(totalTime));
    message(QString("单个文件循环写入平均总耗时(包括打开关闭文件): %1ms").arg(fileTotalTime));
    message(QString("每次写入数据平均耗时(包括打开关闭文件: %1ms").arg(fileTotalTime * 1.0f / loopWrite));
    message(QString("==========================测试结束=============================="));

    emit signal_finished();
    return;
}

工程模板

  在这里插入图片描述


后续

  会持续补充测试其他方式,QFile的性能本身并不高。


上一篇:没有了
下一篇:《文件IO操作开发笔记(二):使用Cpp的ofstream对磁盘文件存储进行性能测试以及测试工具


文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/128438303

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
QtQFile 类提供了一种方便的方式来访问和操作文件。它支持文件的读写、复制、移动、删除等操作。下面是 QFile 的一些常用方法和详细介绍。 1. 打开和关闭文件 QFile 可以通过构造函数或 open() 方法打开一个文件。例如: ```cpp QFile file("test.txt"); if (file.open(QIODevice::ReadOnly)) { // 文件打开成功,进行读取操作 file.close(); } ``` 在上面的例子中,我们使用了 `QIODevice::ReadOnly` 标志来指示文件只能读取,不能写入。其他可用的标志包括 `QIODevice::WriteOnly`、`QIODevice::ReadWrite`、`QIODevice::Append` 等。当文件打开成功后,我们需要在操作完成后使用 `close()` 方法关闭文件。 2. 读取文件内容 QFile 可以使用 `readAll()` 方法一次性读取整个文件的内容: ```cpp QFile file("test.txt"); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); // 处理读取的数据 file.close(); } ``` 也可以使用 `read()` 方法读取部分文件内容: ```cpp QFile file("test.txt"); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.read(1024); // 处理读取的数据 file.close(); } ``` 其中,`1024` 表示要读取的字节数。如果需要一行一行地读取文件内容,可以使用 `readLine()` 方法: ```cpp QFile file("test.txt"); if (file.open(QIODevice::ReadOnly)) { while (!file.atEnd()) { QByteArray line = file.readLine(); // 处理读取的一行数据 } file.close(); } ``` 上面的代码片段将逐行读取文件的内容,直到文件末尾。 3. 写入文件内容 QFile 可以使用 `write()` 方法写入数据到文件中: ```cpp QFile file("test.txt"); if (file.open(QIODevice::WriteOnly)) { QByteArray data = "Hello, world!"; file.write(data); file.close(); } ``` 如果需要在文件末尾追加数据,可以使用 `QIODevice::Append` 标志打开文件,然后使用 `write()` 方法写入数据。 4. 复制、移动和删除文件 QFile 可以使用 `copy()` 方法复制文件: ```cpp QFile file("test.txt"); if (file.copy("copy.txt")) { // 文件复制成功 } ``` 可以使用 `rename()` 方法移动或重命名文件: ```cpp QFile file("test.txt"); if (file.rename("newname.txt")) { // 文件移动或重命名成功 } ``` 可以使用 `remove()` 方法删除文件: ```cpp QFile file("test.txt"); if (file.remove()) { // 文件删除成功 } ``` 以上是 QFile 类的一些常用方法,可以根据需要进行调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙红胖子Qt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值