1. 程式人生 > >QT框架下的文字操作(一)

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

簡介

檔案操作作為軟體開發中不可或缺的一環,將其獨立出來並形成一個模組就顯得十分必要。這樣不僅易於維護管理,而且易於在專案中整合。

文字型別

常用的文字型別包括:

  • 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:本人很少寫部落格,以後有空會常寫,如有不當之處還請大家指教-。-

本小節先寫到這,完整的文字操作原始碼,點選此處下載。