QT框架下的文本操作(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w2014qian/article/details/83145724

简介

文件操作作为软件开发中不可或缺的一环,将其独立出来并形成一个模块就显得十分必要。这样不仅易于维护管理,而且易于在项目中集成。

文本类型

常用的文本类型包括:

  • csv文件
  • dbf 文件
  • excel 文件
  • ini 文件
  • json 文件
  • xml 文件

文本操作

  • csvdbfinijsonxml文件
    • 读取
    • 写入
  • excel 文件
    • 读取
    • 写入
    • 格式设置
    • 插入图表

代码实现

csv文件

csv文件的实质就是在每行的各项数据之间添加逗号分隔符 ,,所有我们直接使用 QFileQTextStream 去实现读写。

文件打开

在头文件中

	QFile* m_CSVFile;
	QTextStream* m_textStream;

在cpp中

	m_CSVFile = new QFile(fileName);
	if (!m_CSVFile->open(flag))
		qDebug() << "open failed:" << m_CSVFile->error();
	m_textStream = new QTextStream(m_CSVFile);

其中,fileName为文件名,flag为文件打开模式,类型为 QIODevice::OpenModeFlag

    enum OpenModeFlag {
        NotOpen = 0x0000,
        ReadOnly = 0x0001,
        WriteOnly = 0x0002,
        ReadWrite = ReadOnly | WriteOnly,
        Append = 0x0004,
        Truncate = 0x0008,
        Text = 0x0010,
        Unbuffered = 0x0020
    };

文件写入

bool CsvUtil::setCSVData(const QList<QVariantList>& CSVList,bool overWrite) {
	if (CSVList.empty()) 
		return false;

	if (!m_CSVFile->isOpen()) 
		return false;

	if (overWrite && !m_CSVFile->resize(0)) 
		return false;

	QString lineString = "";
	bool isFirst = true;
	Q_FOREACH(const QVariantList& lineData, CSVList) { 
		lineString = "";
		isFirst = true;
		Q_FOREACH (const QVariant& unitData,lineData) {
			if (!isFirst)
				lineString += ",";
			isFirst = false;
			lineString += unitData.toString();
		}
		lineString += "\n";
		m_CSVFile->write(lineString.toLocal8Bit());
	}
	m_CSVFile->flush(); 
	return true; 
}

其中,CSVList中的每一个元素为要写入的一行的数据,overWrite决定是否需要覆盖文本中的原有数据。

文件读取

// 获取第lineNum行的数据
QStringList CsvUtil::getCSVData(int lineNum)
{
	m_textStream->seek(0);
	int lineCount = 0;

	QString lineData = "";
	while (!m_textStream->atEnd())
	{
		lineData = m_textStream->readLine();
		if (lineNum == lineCount)
			return lineData.split(",");
		lineCount++;
	}

	return QStringList();
}
// 获取文件所有数据
QList<QStringList> CsvUtil::getAllCSVData()
{
	QList<QStringList> CSVList;
	m_textStream->seek(0);

	QString lineData = "";
	while (!m_textStream->atEnd())
	{
		lineData = m_textStream->readLine();
		CSVList.push_back(lineData.split(","));
	}
	return CSVList;
}

dbf文件

DBF文件是一种以二进制进行存储的表格数据文件,其文件内部有着严格的格式要求,具体由文件头和记录项组成。具体参考 DBF文件格式说明

我们这里使用第三方库 QDbf 来实现对dbf文件的读写。
QDbf github地址: https://github.com/IvanPinezhaninov/QDbf.

文件打开

在头文件中

QDbf::QDbfTable m_table;

在cpp中

// fileName:文件名,openMode:打开模式(QDbf::QDbfTable::OpenMode)
// fileCode:文件编码(QDbf::QDbfTable::Codepage)
if (!m_table.open(fileName, openMode))
	qDebug() << QString("open dbf file failed,fileName:%1").arg(fileName);
if (!m_table.setCodepage(fileCode))
	qDebug() << QString("set dbf file code failed,fileName:%1").arg(fileName);

其中:

    enum OpenMode {
        ReadOnly = 0,
        ReadWrite
    };
    enum Codepage {
        CodepageNotSet = 0,
        IBM437,
        IBM850,
        IBM866,
        Windows1250,
        Windows1251,
        Windows1252,
        GB18030,
        UnsupportedCodepage
    };

文件读取

// @params: dataMaps:返回的一行一行的数据,key:列名,rowIndex:行序号,columnIndex:列序号
bool DbfUtil::getValue(QList<QVariantMap> &dataMaps, int beginRowIndex, int endRowIndex,
	int beginColumnIndex, int endColumnIndex) {
	dataMaps.clear();
	if (!isOpen() || !m_table.seek(-1))
		return false;

	QVariantMap dataMap;
	int rowIndex = -1, columnIndex = 0;
	while (m_table.next()) {
		rowIndex++;
		if (rowIndex < beginRowIndex)
			continue;
		if (rowIndex > endRowIndex)
			break;

		dataMap.clear();
		QDbf::QDbfRecord record = m_table.record();
		for (columnIndex = 0; columnIndex < record.count(); columnIndex++) {
			if (columnIndex < beginColumnIndex)
				continue;
			if (columnIndex > endColumnIndex)
				break;

			dataMap.insert(record.fieldName(columnIndex), record.value(columnIndex));
		}
		dataMaps.append(dataMap);
	}

	return true;
}
// @params: dataMaps:返回的一行一行的数据,key:列名,rowIndex:行序号,columnNames:列名
bool DbfUtil::getValue(QList<QVariantMap> &dataMaps, int beginRowIndex, int endRowIndex,
	const QStringList &columnNames) {
	dataMaps.clear();
	if (!isOpen() || !m_table.seek(-1))
		return false;

	QVariantMap dataMap;
	int rowIndex = -1, columnIndex = 0;
	while (m_table.next()) {
		rowIndex++;
		if (rowIndex < beginRowIndex)
			continue;
		if (rowIndex > endRowIndex)
			break;

		dataMap.clear();
		QDbf::QDbfRecord record = m_table.record();
		for (columnIndex = 0; columnIndex < record.count(); columnIndex++) {
			if (!columnNames.contains(record.fieldName(columnIndex)))
				continue;

			dataMap.insert(record.fieldName(columnIndex), record.value(columnIndex));
		}
		dataMaps.append(dataMap);
	}

	return true;
}

文件修改

写入

添加多行数据:

// @param dataMaps中的元素为一行数据
bool DbfUtil::addValue(const QList<QVariantMap> &dataMaps) {
	if (!isOpen() || !m_table.last())
		return false;

	Q_FOREACH(const QVariantMap &dataMap, dataMaps) {
		if (!m_table.addRecord())
			return false;

		for (auto it = dataMap.constBegin(); it != dataMap.constEnd(); it++) {
			if (!m_table.setValue(it.key(), it.value()))
				return false;
		}
	}

	return true;
}

插入一行数据:

// @param dataMap:行数据,rowIndex:插入位置的行序号
bool DbfUtil::insertValue(const QVariantMap &dataMap, int rowIndex) {
	if (!isOpen() || !m_table.seek(rowIndex - 1))
		return false;

	if (!m_table.addRecord())
		return false;

	for (auto it = dataMap.constBegin(); it != dataMap.constEnd(); it++) {
		if (!m_table.setValue(it.key(), it.value()))
			return false;
	}
	return true;
}

修改行数据:

// @param dataMap:行数据,rowIndex:修改位置的行序号,为-1时,修改所有行
bool DbfUtil::updateValue(const QVariantMap &dataMap, int rowIndex) {
	if (!isOpen() || !m_table.seek(rowIndex))
		return false;

	// 修改所有行
	if (-1 == rowIndex) {
		while (m_table.next()) {
			for (auto it = dataMap.constBegin(); it != dataMap.constEnd(); it++) {
				if (!m_table.setValue(it.key(), it.value()))
					return false;
			}
		}
	}
	// 修改指定行
	else {
		for (auto it = dataMap.constBegin(); it != dataMap.constEnd(); it++) {
			if (!m_table.setValue(it.key(), it.value()))
				return false;
		}
	}
	return true;
}

删除

删除行数据:

// @param rowIndex:删除位置的行序号,为-1时,删除所有行	
bool DbfUtil::removeValue(int rowIndex) {
	if (!isOpen() || !m_table.seek(rowIndex))
		return false;

	// 删除所有行
	if (-1 == rowIndex) {
		while (m_table.next()) {
			if (!m_table.removeRecord())
				return false;
		}
		return true;
	}
	// 删除指定行
	else {
		return m_table.removeRecord();
	}
}

PS:本人很少写博客,以后有空会常写,如有不当之处还请大家指教-。-

本小节先写到这,完整的文本操作源码,点击此处下载。

猜你喜欢

转载自blog.csdn.net/w2014qian/article/details/83145724