qt初入门1:qt读文件的几种方式简单整理

工作变动开始接触qt,涉及到qt读文件相关业务,简单整理一下qt读文件几种方式,后面发现有其他的再新增

1:使用qt读文件显示在界面的时候发现特别慢(实际是界面显示过多/日志打印导致)

测试demo的方式归纳汇总几种读qt文件的方法

1:获取文件源按钮,并打印获取到的相关文件名
2:使用qfile直接读文件,显示耗时时间
3:使用qdatastream读文件,显示耗时时间
4:使用qtextstrean读文件,显示耗时时间
5:使用内存映射 Qfile::map 内存映射读文件,这里的map实际是Qfile的基类中的

2:qflie直接读文件

按行读取,read按字节读取,readAll读全部几种方式

void frmReadFile::on_qfileReadFileButton_clicked()
{
    //使用qfile readline /readAll
    QFile file_read(m_filename);
    if(!file_read.exists()) {
        return;
    }

    if (!file_read.open(QIODevice::ReadOnly))  {
        QMessageBox::warning(this, "警告", "文件打不开!");
        return;
    }
    
//按行读取的方式
//    QByteArray readdata_array;
//    while(!file_read.atEnd())
//    {
//        readdata_array = file_read.readLine();
//        //真正的耗时在显示在控件上 如果增加显示在控件上 可能需要耗时22s
//        ui->printTextEdit->append(readdata_array.toHex(' '));
//        qDebug()<<"read file size:"<<readdata_array.size();
//        readdata_array.clear();
//    }
//read读取特定字节
    int readlength = 0;
    QByteArray byte_data;
    byte_data.resize(1000);
    while((readlength=file_read.read(byte_data.data(),1000))!=0) // 一次读进1000个字节(读进1000个字节,length==1000),当剩余字节数小于1000时,length等于剩余字节数
    {
        this->append(QString(byte_data.toHex(' ')));
    }

//readall直接读取全部内容
// 	  QByteArray readdata_array;
//    file_read.seek(0);
//    readdata_array= file_read.readAll();
//    ui->printTextEdit->append(readdata_array.toHex(' '));

//    qDebug()<<"read file size:"<<readdata_array.size() <<"data is:"<<readdata_array.toHex(' ');
//    readdata_array.clear();
    file_read.close();
}

3:qTextStream读文件

借助readLine readAll read 可以实现文件读取

通过用QElapsedTimer增加耗时,分析出文件处理真正耗时在内容显示上。

写时发现待处理问题:打开文件的方式,以及读取显示中文的demo。

void frmReadFile::on_qTextStrReadFileButton_clicked()
{
    QFile file_read(m_filename);
    if(!file_read.exists()) {
        return;
    }

    if (!file_read.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this, "警告", "文件打不开!");
        return;
    }

    //读取并显示在控件上 耗时7s
    QElapsedTimer lost_time;
    lost_time.start();
    QString read_data= "";
    
    QTextStream out(&file_read);
    while(!out.atEnd())
    {
        read_data += out.readLine();
       // ui->printTextEdit->append(read_data); //耗时7s
    }
   
    QString qfile_lost_time = "qtextstream 读取文件耗时:";
    qfile_lost_time += QString::number(lost_time.elapsed());
    qfile_lost_time += "毫秒";
    ui->TestTextEdit->append(qfile_lost_time);

    //先读取再显示的方案  读取耗时59ms  主要显示也都是乱码
    //这里如果转成16进制进行输出  内存占用太大太大  会导致程序卡死
//    ui->printTextEdit->append(read_data.toLatin1().toHex());
    ui->printTextEdit->append(read_data);
    file_read.close();
}

4:qdatastream读文件

可以通过readBytes, readRawData实现文件的读取

写时发现待处理问题:遇到过open文件时选择打开方式 如果以Text方式打开,流显示换行符号会是两个字节,所以在处理读文件时,open函数的参数要注意

//使用qdatastream进行读文件
//耗时挺短的  读文件并不怎么耗时  耗时在处理显示上
void frmReadFile::on_qdataStrReadFileButton_clicked()
{
    QFile file_read(m_filename);
    if(!file_read.exists()) {
        return;
    }

    if (!file_read.open(QIODevice::ReadOnly)){
        QMessageBox::warning(this, "警告", "文件打不开!");
        return;
    }

    QElapsedTimer lost_time;
    lost_time.start();

    QDataStream out(&file_read);
    QByteArray read_data;
    read_data.resize(file_read.size());
    //一次性读取内容过多  导致文件读不出来
    while(!out.atEnd())
    {
        out.readRawData(read_data.data(), file_read.size());
    }

    QString qfile_lost_time = "qdatastream 读取文件耗时:";
    qfile_lost_time += QString::number(lost_time.elapsed());
    qfile_lost_time += "毫秒";
    ui->TestTextEdit->document()->setMaximumBlockCount(100);
    ui->TestTextEdit->append(qfile_lost_time);

    qDebug()<<"read file size:"<<read_data.size();
    //这里进行显示的时候如果过大总会崩溃  ===》内容过大到界面显示的问题
    ui->printTextEdit->document()->setMaximumBlockCount(100);
    ui->printTextEdit->append(read_data.toHex(' '));
    lost_time.restart();
   //TODO 1:研究一下通过信号触发容器的写入  2:研究一下QByteArray转成带空格的耗时
    file_read.close();
}

5:内存映射的方式读文件

其实就是把指针映射到文件的对应位置,然后相关的操作就和操作内存指针一样了。

主要用到了 QFileDevice 类的 map 和unmap

//内存映射的方法读文件
void frmReadFile::on_qmapReadFileButton_clicked()
{
    //采用内存映射的方法进行
    QFile file_read(m_filename);
    if (!file_read.open(QIODevice::ReadOnly))
    {
        QMessageBox::warning(this, "警告", "文件打不开!");
        return;
    }

    QElapsedTimer lost_time;
    lost_time.start();
    
    int file_size = file_read.size();
    uchar* ptr = file_read.map(0, file_read.size());
    uchar* flag_ptr = ptr;
    //这里先关闭文件对读文件不影响
    
    int temp = 0;
    QByteArray flag_data;
    flag_data.resize(1000);
    while(temp < file_size)
    {
        memcpy(flag_data.data(), flag_ptr+temp, 1000);
        temp += 1000;
        //这里对数据进行处理
        //TODO  这里的打印会导致qt工具打印过多日志  其他工具崩溃
//        qDebug()<<"file map data0 is"<<flag_data;
//        ui->printTextEdit->append(flag_data.toHex());
        //这里如果读取文件过大  也会让程序占用的内存大

        this->append(QString(flag_data.toHex(' ')));
    }

    if(temp>file_size)
    {
        memcpy(flag_data.data(), flag_ptr+(file_size-file_size%1000), file_size%1000);
        qDebug()<<"file map data1 is"<<flag_data;
        ui->printTextEdit->append(flag_data.toHex(' '));
//        this->append(QString(flag_data.toHex(' ')));
    }
    
    QString qfile_lost_time = "qfile map 读取文件耗时:";
    qfile_lost_time += QString::number(lost_time.elapsed());
    qfile_lost_time += "毫秒";
    qfile_lost_time += QString::number(file_size/1000);
    qfile_lost_time += "行";
    ui->TestTextEdit->append(qfile_lost_time);

    file_read.unmap(ptr);
    if(ptr!=NULL)
    {
        ptr = NULL;
        qDebug()<<"umap is not null";
    }

    file_read.close();
}

6:总结

这些demo测试的初衷是,初次接触qt,要处理一批大文件后,进行界面的显示,但是发现,读取大文件时,有崩溃,耗时的问题

排查耗时崩溃问题的原因,有怀疑过是读文件的耗时,所以做了简单demo测试,最后发现是字符处理内存增加,qDebug日志记录,通过ui进行界面显示过大内容导致的耗时,甚至崩溃。

在整理回头整理demo的过程,以及最近实际过程中遇到的小问题,发现可以整理的点

1:open的时候,打开方式按默认,文本方式,流的方式打开,对后面文件处理有影响(例如,以文本方式打开,但是用qdatastream处理流的时候发现,换行符变成了两个字符)。

2:几种方式排查后,读文件并不耗时,可以整理几种读文件方式的原理。

3:研究几种读文件后,字符处理中文显示问题。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载食用体验! 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。在使用过程中,如有问题或建议,请及时沟通。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【项目介绍】 C++课程作业-基于Qt实现的链表操作演示系统源码(含详细注释+报告).zip 1.1 题目 分别以单链表、循环链表、双向链表为例,实现线性表的建立、插入、删除、查找等基 本操作。 要求:能够把建立、插入、删除等基本操作的过程随时显示输出来。 1.2 软件功能 对于单链表、循环链表和双向链表,均能实现以下功能: (1)线性表的建立,建立一个带头结点的空链表; (2)线性表插入操作,输入插入索引与插入元素值,将元素插入到链表指定位置; (3)线性表删除操作,输入删除元素的索引,删除该位置的元素; (4)线性表查找操作,输入要查找的元素值,返回第一个等于该值得元素索引; (5)线性表修改操作,输入要修改的索引与修改后的值,修改线性表对应元素; (6)能够对各种特殊情况如索引不合法等进行判断并给出提示。 1.3 设计思想 根据题意,需要对不同链表进行同样的几项基本操作,实现标准交互式图形界面,可以 分为算法设计和界面设计两部分。 算法设计方面:对于单链表,本程序链表的建立采用带头结点方式,即每次建立链表都 动态申请一个头结点,头结点的后继是 NULL;链表的插入操作需要从头遍历链表,在指定 索引处修改插入位置前驱结点的 next 指针指向新结点,新结点的 next 指针则指向该位置原 结点;链表的删除操作同样需要从头遍历链表,将指定索引处结点的前驱结点的 next 指针 修改为指向该结点的后继结点,并删除当前结点即可;链表的查找操作需要从头遍历链表比 较当前访问元素与要查找元素是否相等,若相等则返回索引,若访问完整个链表都找不到相 同的元素,则提示查找失败;链表修改操作无需改变链表长度,从头遍历链表找到对应位置 元素修改其值即可。循环链表和双向链表的相关操作基本同单链表,不同的是循环链表最后 一个结点的 next 指针指向头结点,双向链表除了指向元素后继的 next 指针还有指向元素前 驱的 prior 指针。三种链表的实现有所不同,但对于本程序的场景体现不出三种链表的差异。 界面设计方面:可以利用 QT 框架添加按钮、选择框、文本展示框等控件,将三种链表 的五项基本操作整合到一个界面中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值