Qt读写CSV文件的三种方式及优劣对比
作者:luoyayun361
前言
作为一种常见的数据交换格式,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文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!