简介
文件操作作为软件开发中不可或缺的一环,将其独立出来并形成一个模块就显得十分必要。这样不仅易于维护管理,而且易于在项目中集成。
文本类型
常用的文本类型包括:
- csv文件
- dbf 文件
- excel 文件
- ini 文件
- json 文件
- xml 文件
文本操作
- csv、dbf、ini、json、xml文件
- 读取
- 写入
- excel 文件
- 读取
- 写入
- 格式设置
- 插入图表
代码实现
csv文件
csv文件的实质就是在每行的各项数据之间添加逗号分隔符 ,,所有我们直接使用 QFile 和 QTextStream 去实现读写。
文件打开
在头文件中
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:本人很少写博客,以后有空会常写,如有不当之处还请大家指教-。-
本小节先写到这,完整的文本操作源码,点击此处下载。