以下是使用 QXlsx 读取 XLSX 文件数据的详细代码示例,包含注释说明和常见场景处理:
代码示例:读取 Excel 文件数据
#include <QCoreApplication>
#include <QXlsx/xlsxdocument.h>
#include <QDebug>
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
// 1. 加载 Excel 文件
QString filePath = "EmployeeData.xlsx";
QXlsx::Document xlsx(filePath);
// 检查文件是否加载成功
if (!xlsx.isLoaded()) {
qDebug() << "错误:无法加载文件" << filePath;
qDebug() << "可能原因:文件不存在、路径错误或权限不足。";
return -1;
}
// 2. 获取所有工作表名称,并遍历每个工作表
QStringList sheetNames = xlsx.sheetNames();
qDebug() << "工作表列表:" << sheetNames;
foreach (const QString &sheetName, sheetNames) {
qDebug() << "\n===== 正在读取工作表:" << sheetName << "=====";
// 切换到当前工作表
xlsx.setCurrentSheet(sheetName);
// 3. 获取工作表的行数和列数
QXlsx::CellRange range = xlsx.dimension();
int rowCount = range.rowCount();
int colCount = range.columnCount();
qDebug() << "总行数:" << rowCount << "总列数:" << colCount;
// 4. 逐行逐列读取数据
for (int row = 1; row <= rowCount; ++row) {
QString rowData;
for (int col = 1; col <= colCount; ++col) {
// 读取单元格内容
QVariant cellValue = xlsx.read(row, col);
// 处理不同类型的数据
if (cellValue.isValid()) {
// 日期类型处理
if (cellValue.type() == QVariant::DateTime) {
QDateTime dt = cellValue.toDateTime();
rowData += dt.toString("yyyy-MM-dd") + "\t";
}
// 数字或文本类型
else {
rowData += cellValue.toString() + "\t";
}
qDebug() << QString("单元格 [%1, %2] 数据:%3")
.arg(row)
.arg(col)
.arg(cellValue.toString());
} else {
rowData += "(空)\t"; // 标记空单元格
}
}
qDebug().noquote() << "行" << row << ":" << rowData;
}
// 5. 检查合并单元格
QList<QXlsx::CellRange> mergedCells = xlsx.mergedCells();
if (!mergedCells.isEmpty()) {
qDebug() << "\n合并单元格区域:";
foreach (const QXlsx::CellRange &merged, mergedCells) {
QString mergedInfo = QString("区域: %1-%2, 值: %3")
.arg(merged.topLeft().toString())
.arg(merged.bottomRight().toString())
.arg(xlsx.read(merged.topLeft()).toString());
qDebug() << mergedInfo;
}
}
}
return 0;
}
关键功能说明
-
文件加载与错误处理:
- 使用
QXlsx::Document
直接加载文件。 - 通过
isLoaded()
检查是否成功加载,避免因路径错误导致崩溃。
- 使用
-
多工作表支持:
- 通过
sheetNames()
获取所有工作表名称。 - 使用
setCurrentSheet()
切换工作表,确保读取正确内容。
- 通过
-
动态获取行列范围:
dimension()
返回工作表的单元格范围,获取工作表的行数和列数,自动适应数据区域。- 通过双重循环遍历所有单元格。
-
读取单元格数据:
- 使用
xlsx.read(row, col)
读取指定单元格内容。 - 返回值为
QVariant
,支持多种数据类型(文本、数字、日期等)。 - 使用
cellValue.isValid()
检查单元格是否有数据,也即检查单元格是否为空。
- 使用
-
数据类型处理:
- 文本/数字:直接通过
toString()
转换。 - 日期:识别
QVariant::DateTime
类型,格式化为易读字符串。 - 空单元格:用
(空)
标记,避免遗漏数据。
- 文本/数字:直接通过
-
合并单元格检测:
- 使用
mergedCells()
获取所有合并区域。 - 输出合并区域的左上角值和范围(如 “A1:C1”)。
- 使用
示例文件内容
假设 EmployeeData.xlsx
内容如下:
姓名 | 年龄 | 入职日期 |
---|---|---|
张三 | 28 | 2020-05-10 |
李四 | 35 | 2018-09-01 |
合并单元格:A4:C4 -> “备注:所有员工为全职” |
输出结果
工作表列表: ("Sheet1")
===== 正在读取工作表: Sheet1 =====
总行数:4 总列数:3
行1 : 姓名 年龄 入职日期
行2 : 张三 28 2020-05-10
行3 : 李四 35 2018-09-01
行4 : 备注:所有员工为全职 (空) (空)
合并单元格区域:
区域: A4-C4, 值: 备注:所有员工为全职
常见问题处理
-
文件路径问题:
- 如果文件不在程序运行目录,需使用绝对路径(如
C:/data/file.xlsx
)。
- 如果文件不在程序运行目录,需使用绝对路径(如
-
日期显示异常:
- Excel 内部以浮点数存储日期,QXlsx 自动转换为
QDateTime
,格式化为yyyy-MM-dd
更直观。
- Excel 内部以浮点数存储日期,QXlsx 自动转换为
-
公式结果读取:
- 若单元格包含公式(如
=SUM(A1:A3)
),QXlsx 默认读取公式本身,非计算结果。 - 解决方案:手动计算(需复杂逻辑)或用 Excel 打开文件后保存,QXlsx 读取结果值。
- 若单元格包含公式(如
-
性能优化:
- 对于大型文件(如 10 万行),逐行读取可能较慢。可限制读取范围(如
row <= 1000
)或按需读取特定列。
- 对于大型文件(如 10 万行),逐行读取可能较慢。可限制读取范围(如
扩展功能示例
读取特定区域的单元格格式
// 获取单元格格式
QXlsx::Format format = xlsx.cellFormat(row, col);
if (format.isValid()) {
qDebug() << "字体加粗:" << format.fontBold();
qDebug() << "背景颜色:" << format.patternBackgroundColor();
}
按列名读取数据(假设第一行为列名)
QMap<QString, int> columnMap; // 存储列名与列号的映射
// 第一行为列头
for (int col = 1; col <= colCount; ++col) {
QString header = xlsx.read(1, col).toString();
columnMap[header] = col;
}
// 读取“年龄”列的所有数据
for (int row = 2; row <= rowCount; ++row) {
int age = xlsx.read(row, columnMap["年龄"]).toInt();
qDebug() << "第" << row << "行年龄:" << age;
}
通过以上代码,你可以灵活读取 Excel 文件中的结构化数据,适用于数据导入、报表分析等场景。如需更多高级操作,可参考 QXlsx 官方文档。