Qt读写CSV文件的三种方式及优劣对比

 更新时间:2023年11月24日 11:30:47   作者:luoyayun361  
最近的要用到CSV格式的数据,所以这篇文章讲述一下QT读取CSV文件数据,下面这篇文章主要给大家介绍了关于Qt读写CSV文件的三种方式及优劣对比的相关资料,需要的朋友可以参考下

前言

作为一种常见的数据交换格式,CSV(Comma Separated Values)文件常常用于数据导出和导入等场合。在实际开发中,我们也需要使用Qt来实现CSV文件的读写操作。本篇博客将介绍使用Qt实现CSV读写的方法,并分析每种实现方式的优缺点。

一、使用QStringList及QTextStream实现CSV文件读写

本方法使用QStringList来保存每行数据,使用QTextStream类读写文本文件。具体实现代码如下:

// 读取CSV文件
bool readCsv(QString filePath, QList<QStringList>& data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return false;

    QTextStream stream(&file);
    while (!stream.atEnd())
    {
        QString line = stream.readLine();
        QStringList row = line.split(',', Qt::SkipEmptyParts);
        data.append(row);
    }

    file.close();
    return true;
}

// 写入CSV文件
bool writeCsv(QString filePath, QList<QStringList>& data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;

    QTextStream stream(&file);
    for (int i = 0; i < data.size(); i++)
    {
        QStringList row = data.at(i);
        for (int j = 0; j < row.size(); j++)
        {
            stream << row.at(j);
            if (j < row.size() - 1)
                stream << ",";
        }
        stream << "\n";
    }

    file.close();
    return true;
}

该示例代码运用了QTextStream的readLine()和<<运算符来实现CSV文件数据的读写。需要注意的是,在读取CSV文件时,要使用QStringList的split()函数来将每行拆分为多个字符串,并用字符串列表保存。在写入CSV文件时,要使用QStringList的join()函数来将每行数据转为字符串,并用逗号分隔,产生一条CSV行,最后一行不应该有逗号。

优点:

  • 实现简单:使用QStringList和QTextStream实现CSV读写操作非常简单,能够快速上手;
  • 代码量少:相对其他实现方式,该方法实现的代码量较少。

缺点:

  • 写入数据顺序不能改变:当数据量大的时候,使用该方法逐行写入文件,文件I/O开销相对较大,导致写入速度变慢。同时,该实现方式要求数据顺序不能改变,因为每行数据只存储在单独的QStringList中。

二、使用QTextCodec及QByteArray实现CSV文件读写

本方法使用QTextCodec来处理编码问题,并使用QByteArray来读写文件。具体实现如下:

// 读取CSV文件
bool readCsv(QString filePath, QList<QStringList>& data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly))
        return false;

    QTextCodec* codec = QTextCodec::codecForName("UTF-8");   // 使用UTF-8编码
    QByteArray content = file.readAll();
    QString text = codec->toUnicode(content);
    QStringList lines = text.split('\n');

    for (int i = 0; i < lines.size(); i++)
    {
        if (!lines.at(i).isEmpty())
        {
            QStringList row = lines.at(i).split(',');
            data.append(row);
        }
    }

    file.close();
    return true;
}

// 写入CSV文件
bool writeCsv(QString filePath, QList<QStringList>& data)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly))
        return false;

    QTextCodec* codec = QTextCodec::codecForName("UTF-8");   // 使用UTF-8编码

    for (int i = 0; i < data.size(); i++)
    {
        QStringList row = data.at(i);
        QString line = row.join(",");
        line += "\n";
        QByteArray encodedLine = codec->fromUnicode(line);
        file.write(encodedLine);
    }

    file.close();
    return true;
}

该示例代码在读取CSV文件时使用了QTextCodec的codecForName()方法来指定文件编码为UTF-8,使用QByteArray类保存文件数据,通过QTextCodec::toUnicode()函数将字节数组转换成QString对象。在写入CSV文件时,使用QByteArray类保存每行数据,并将数据编码成字节数组后写入文件。

优点:

  • 适用性广泛:该实现方式适用性广泛,可以处理各种不同的字符编码;
  • 写入速度快:使用QByteArray类来读写文件,文件I/O开销相对较少。

缺点:

  • 实现复杂:相对于第一种实现方式,该方法需要处理编码问题和字节流转换问题,因此实现方式相对复杂一些。

三、使用QStandardItemModel实现CSV文件读写

本方法使用QStandardItemModel来保存每行数据,并使用QTextStream来读写文件。具体实现如下:

// 读取CSV文件
bool readCsv(QString filePath, QStandardItemModel* model)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return false;

    QTextStream stream(&file);
    while (!stream.atEnd())
    {
        QString line = stream.readLine();
        QStringList row = line.split(',', Qt::SkipEmptyParts);
        QList<QStandardItem*> items;
        for (int i = 0; i < row.size(); i++)
        {
            QStandardItem* item = new QStandardItem(row.at(i));
            items.append(item);
        }
        model->appendRow(items);
    }

    file.close();
    return true;
}

// 写入CSV文件
bool writeCsv(QString filePath, QStandardItemModel* model)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;

    QTextStream stream(&file);
    for (int i = 0; i < model->rowCount(); i++)
    {
        QStringList row;
        for (int j = 0; j < model->columnCount(); j++)
        {
            QString cell = model->index(i, j).data().toString();
            row.append(cell);
        }
        stream << row.join(",") << "\n";
    }

    file.close();
    return true;
}

该示例代码使用了QStandardItemModel类来保存每行数据,并使用QTextStream类读写文件。在读取CSV文件时,使用QStandardItemModel的appendRow()函数向模型中添加新行,并在每行中保存对应的QStandardItem对象的指针。在写入CSV文件时,从QStandardItemModel中取出每个单元格的数据,将其转换成字符串后,保存到QStringList中,并使用QTextStream类的<<运算符将数据写入到文件中。

优点:

  • 具有更好的扩展性:相对于前两种实现方式,使用QStandardItemModel实现CSV读写操作具有更好的扩展性和灵活性;
  • 数据顺序可改变:使用QStandardItemModel保存数据可以方便地改变数据顺序,并且可以添加自定义的数据项(例如:QComboBox)。

缺点:

  • 实现相对复杂:相对于前两种实现方式,使用QStandardItemModel实现CSV读写操作需要考虑到数据处理和模型层次结构的复杂性;
  • 内存消耗较大:使用QStandardItemModel来保存每行数据,可能会导致内存消耗较大。

附:QT读取csv文件并且绘制折线图

void MainWindow::readcsvfile() //读取csv
{
 QFile csvFile("C:/Users/Administrator/Desktop/Demo/0702.CSV");
 QStringList csvList;
 csvList.clear();
 if (csvFile.open(QIODevice::ReadWrite)) //对csv文件进行读写操作
 {
  QTextStream stream(&csvFile);
  while (!stream.atEnd())
 {
 csvList.push_back(stream.readLine()); //保存到List当中
 }
 csvFile.close();
 }
 else
 {
	 QMessageBox::about(NULL, "csv文件", "未打开该文件!");
 }
   int i = 0;
   Q_FOREACH(QString str, csvList)   //遍历List
  {
   i = i + 1;
   QStringList valsplit = str.split(","); //分隔字符串
   if(i > 2)
   {
    //得到深度、声速、温度
    QString depth = valsplit[0];
    QString sonicvelocity = valsplit[1];
    QString temperature = valsplit[2];
    double depthvalue = depth.toDouble();
    double sonicvalue = sonicvelocity.toDouble();
    double tempvalue = temperature.toDouble();
	//Q//MessageBox::warning(NULL, "dd", QString::number(tempvalue));
	QPointF point;
    point.setX(depthvalue);
    point.setY(sonicvalue);
	QPointF point2;
	point2.setX(depthvalue);
	point2.setY(tempvalue + 1510);
    vectors.append(point);
	vector2.append(point2);
   }
  }
}
 
void MainWindow::lineChart() //绘制图
{
    //设置X,Y标题
    ui->qwtPlot->setAxisTitle(QwtPlot::xBottom, QString::fromLocal8Bit("深度(m)"));
    ui->qwtPlot->setAxisTitle(QwtPlot::yLeft, QString::fromLocal8Bit("声速(m/s)"));
    ui->qwtPlot->setAxisTitle(QwtPlot::yRight, QString::fromLocal8Bit("温度(°C)"));
    ui->qwtPlot->enableAxis(QwtPlot::yRight,true);
    ui->qwtPlot->setAxisScale(QwtPlot::yLeft,1538,1540,0.2);
    ui->qwtPlot->setAxisScale(QwtPlot::xBottom,0,30,2);
    ui->qwtPlot->setAxisScale(QwtPlot::yRight,28,30,0.2);
 
	//ui->qwtPlot->set
    //构造曲线数据
     QwtPointSeriesData* series = new QwtPointSeriesData(vectors);
	 //设置网格
	 QwtPlotGrid* grid = new QwtPlotGrid();
	 grid->setPen(QColor(222, 222, 222), 1);
	 grid->attach(ui->qwtPlot);
	 //create plot item
     QwtPlotCurve* curve1 = new QwtPlotCurve(QString::fromLocal8Bit("声速"));
     //设置数据
	 curve1->setData(series);
	 //设置画笔颜色==就是图像颜色
	 curve1->setPen(QColor(255, 0, 0), 2, Qt::SolidLine);
	 //使曲线更光滑
	 curve1->setCurveAttribute(QwtPlotCurve::Fitted, true);
	 //把曲线附加到qwtPlot上
     curve1->attach(ui->qwtPlot);
     //添加温度-深度曲线
	 //构造曲线数据
	 QwtPointSeriesData* series2 = new QwtPointSeriesData(vector2);
	 //create plot item
	 QwtPlotCurve* curve2 = new QwtPlotCurve(QString::fromLocal8Bit("温度"));
	 //设置数据
	 curve2->setData(series2);
	 //设置画笔颜色=图像颜色
	 curve2->setPen(QColor(127, 222, 335), 2, Qt::SolidLine);
	 //使曲线更光滑
	 curve2->setCurveAttribute(QwtPlotCurve::Fitted, true);
	 //把曲线附加到qwtPlot上
	 curve2->attach(ui->qwtPlot);
 
	 //设置图例
	 QwtLegend *legend = new QwtLegend;
	 legend->setDefaultItemMode(QwtLegendData::ReadOnly);
	 ui->qwtPlot->insertLegend(legend,QwtPlot::BottomLegend);//插入图例
	 ui->qwtPlot->replot();
     ui->qwtPlot->show();
}

需要第三方库QWT

运行结果:

最后

本篇博客介绍了四种使用Qt实现CSV文件读写操作的方法,分别是:

  • 使用QStringList及QTextStream实现CSV文件读写;
  • 使用QTextCodec及QByteArray实现CSV文件读写;
  • 使用QStandardItemModel实现CSV文件读写;

每种实现方式都有自己的优缺点,在实际开发中可以根据具体应用场景选择适用的实现方法。

总的来说,对于小型数据量的CSV文件,使用QStringList及QTextStream实现CSV文件读写是一个比较好的选择,因为实现相对简单;对于大型数据量的CSV文件,使用QTextCodec及QByteArray可以更快地进行文件I/O操作;使用QStandardItemModel可以更好地处理数据添加、删除、排序等操作,但相对复杂一些。而对于使用频率较高的CSV读写操作,可以考虑使用基于Qt的CSV库或插件,这样可以更快地实现CSV文件读写操作。

当然,在实际开发中还涉及到其他问题,例如文件路径的处理、文件打开失败处理等,本文示例中并未全部涉及,可根据具体应用场景进行扩展。

总结

到此这篇关于Qt读写CSV文件的三种方式及优劣对比的文章就介绍到这了,更多相关Qt读写CSV文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析string 与char* char[]之间的转换

    浅析string 与char* char[]之间的转换

    与char*不同的是,string不一定以NULL('\0')结束。string长度可以根据length()得到,string可以根据下标访问。所以,不能将string直接赋值给char*
    2013-10-10
  • QT自定义之滑动开关

    QT自定义之滑动开关

    这篇文章主要为大家详细介绍了QT自定义之滑动开关效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • 详解C语言之堆栈

    详解C语言之堆栈

    这篇文章主要为大家介绍了C语言的堆栈,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • C语言进阶之内存操作函数详解

    C语言进阶之内存操作函数详解

    这篇文章主要为大家学习介绍了C语言中内存操作函数(memcpy、memmove和memcmp)的使用,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-07-07
  • 基于epoll的多线程网络服务程序设计

    基于epoll的多线程网络服务程序设计

    这篇文章主要为大家详细介绍了基于epoll的多线程网络服务程序设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • QT判断两个日期时间的大小

    QT判断两个日期时间的大小

    本文主要介绍了QT判断两个日期时间的大小,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • 基于C语言实现的迷宫算法示例

    基于C语言实现的迷宫算法示例

    这篇文章主要介绍了基于C语言实现的迷宫算法,结合具体实例形式分析了C语言解决迷宫问题算法的实现技巧与相关注意事项,需要的朋友可以参考下
    2017-09-09
  • OpenCV实现彩色照片转换成素描卡通片

    OpenCV实现彩色照片转换成素描卡通片

    这篇文章主要为大家详细介绍了OpenCV实现彩色照片转换成素描卡通片,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • 深入了解C语言中的动态内存分配

    深入了解C语言中的动态内存分配

    这篇文章主要为大家详细介绍了C语言中的动态内存分配,文中的示例代码讲解详细,对我们学习C语言有一定的帮助,需要的可以参考一下
    2022-06-06
  • 最新C语言自定义类型详解

    最新C语言自定义类型详解

    生活当中有很多物品是不能简单的用整型、浮点型、字符型来区分,它们常常是复杂的集合,比如人,一个人拥有年龄,身高、体重、学历......等信息,我们可以用结构体来实现准确描述人这种复杂集合,这篇文章主要介绍了C语言 自定义类型,需要的朋友可以参考下
    2023-01-01

最新评论