一、QgsProviderMetadata 是什么?
QgsProviderMetadata 是 QGIS 中用于描述和管理数据提供者(Data Provider)的元数据类 。每个支持的数据格式或数据库都有一个对应的 QgsProviderMetadata 对象,它包含了该提供者的基本信息和创建能力。
核心概念
1. 提供者(Provider)的"身份证"
- 存储提供者的唯一标识符(key,如
"postgres"、"ogr"、"wms") - 存储提供者的描述文本(description)
- 存储关联的共享库文件名(library)
2. 懒加载(Lazy Load)机制的核心
"为了节省内存,数据提供者只有在实际使用时才会通过 QLibrary 调用加载。QgsProviderMetadata 提供了足够的信息,以便稍后加载关联的共享库对象。"
这意味着 QGIS 启动时只加载轻量级的元数据,真正的数据库驱动或文件解析库在需要时才加载。
3. 两种类型的提供者
- 基于库的提供者:通过共享库文件(.so/.dll)加载,如 PostgreSQL、GDAL
- 原生提供者:直接集成在 QGIS 核心中,通过函数指针访问,无需单独库文件
二、如何获取 QgsProviderMetadata?
需要通过 QgsProviderRegistry 单例来获取:
cpp
// 获取注册表实例
QgsProviderRegistry* registry = QgsProviderRegistry::instance();
// 通过 provider key 获取元数据
QgsProviderMetadata* metadata = registry->providerMetadata("postgres");
if (metadata) {
qDebug() << "Provider key:" << metadata->key();
qDebug() << "Description:" << metadata->description();
qDebug() << "Library:" << metadata->library();
}
常用的 Provider Key:
| Key | 说明 |
|---|---|
"postgres" |
PostgreSQL/PostGIS 数据库 |
"ogr" |
OGR 矢量格式(Shapefile、GeoPackage等) |
"gdal" |
GDAL 栅格格式 |
"wms" |
Web Map Service |
"wfs" |
Web Feature Service |
"spatialite" |
SpatiaLite 数据库 |
"mssql" |
Microsoft SQL Server |
三、核心方法与使用指南
3.1 基础信息获取
| 方法 | 返回值 | 说明 |
|---|---|---|
key() |
QString |
获取提供者的唯一标识符,如 "postgres" |
description() |
QString |
获取描述性文本,如 "PostgreSQL/PostGIS data provider" |
library() |
QString |
获取共享库文件名,原生提供者返回空字符串 |
3.2 创建连接(最常用)
创建数据库连接:
cpp
// 从 URI 和配置创建连接
QString uri = "host=localhost port=5432 dbname=mydb user=postgres password=secret";
QVariantMap config; // 可选配置,如 {"saveUsername": true}
QgsAbstractProviderConnection* conn = metadata->createConnection(uri, config);
从已保存的连接名创建:
cpp
// 从 QGIS 设置中加载已保存的连接
QgsAbstractProviderConnection* conn = metadata->createConnection("my_postgres_connection");
重要提示 :这些方法可能抛出 QgsProviderConnectionException 异常,必须进行异常处理。
3.3 创建数据提供者实例
cpp
// 创建底层的 QgsDataProvider 对象
QgsDataProvider::ProviderOptions options;
QgsDataProvider* provider = metadata->createProvider(
uri,
options,
QgsDataProvider::ReadFlags()
);
3.4 连接管理(高级功能)
| 方法 | 说明 |
|---|---|
connections(bool cached) |
获取所有已存储的提供者连接 |
dbConnections(bool cached) |
获取数据库类型的连接 |
saveConnection(connection, name) |
将连接保存到 QGIS 设置中 |
deleteConnection(name) |
删除已保存的连接 |
findConnection(name, cached) |
按名称查找连接 |
3.5 URI 编解码
| 方法 | 说明 |
|---|---|
decodeUri(uri) |
将 URI 解析为组件映射(如文件路径、图层名) |
encodeUri(parts) |
将组件映射重新组装为 URI |
3.6 样式管理
| 方法 | 说明 |
|---|---|
loadStyle(uri, errCause) |
从数据源加载图层样式 |
saveStyle(...) |
保存图层样式到数据源 |
listStyles(uri, ...) |
列出数据源中存储的样式 |
deleteStyleById(uri, styleId, errCause) |
删除指定样式 |
四、典型使用流程
cpp
// 1. 获取注册表
QgsProviderRegistry* registry = QgsProviderRegistry::instance();
if (!registry) return;
// 2. 获取特定提供者的元数据
QgsProviderMetadata* metadata = registry->providerMetadata("postgres");
if (!metadata) {
qDebug() << "Provider not found";
return;
}
// 3. 创建连接
QString uri = "host=localhost port=5432 dbname=mydb user=postgres password=secret";
QVariantMap config;
try {
QgsAbstractProviderConnection* baseConn = metadata->createConnection(uri, config);
// 如果是数据库提供者,可以转换为数据库特定接口
QgsAbstractDatabaseProviderConnection* dbConn =
dynamic_cast<QgsAbstractDatabaseProviderConnection*>(baseConn);
if (dbConn) {
// 获取表列表
QList<QgsAbstractDatabaseProviderConnection::TableProperty> tables =
dbConn->tables("public");
for (const auto& table : tables) {
qDebug() << "Table:" << table.tableName();
}
}
delete baseConn; // 记得释放连接
} catch (const QgsProviderConnectionException& e) {
qDebug() << "Connection failed:" << e.what();
}
五、重要注意事项
5.1 异常处理是必须的
createConnection() 等方法在连接失败时会抛出 QgsProviderConnectionException,必须使用 try-catch 捕获,否则程序可能崩溃。
5.2 连接字符串格式敏感
不同提供者对 URI 格式的要求可能不同。PostgreSQL 通常支持以下格式:
host=localhost port=5432 dbname=mydb user=postgres password=secretpostgresql://postgres:secret@localhost:5432/mydb
建议先用 QgsDataSourceUri 构建再获取 connectionInfo():
cpp
QgsDataSourceUri uri;
uri.setConnection(host, port, dbname, user, password);
QString connString = uri.connectionInfo(); // 标准格式
5.3 内存管理
createConnection()返回的指针需要调用者负责删除createProvider()返回的指针同样需要手动释放- 建议使用
std::unique_ptr进行自动管理
5.4 连接对话框问题
某些提供者(如 Oracle)在连接失败时会自动弹出 QGIS 内置的"输入凭据"对话框。如果需要静默验证连接,需要额外处理或在配置中禁用此行为。
5.5 线程安全
QgsProviderMetadata 的方法通常不是线程安全的。在多线程环境中使用时应加锁或在主线程中调用。
5.6 版本兼容性
API 在不同 QGIS 版本间可能有变化:
- QGIS 3.0+:引入了
CreateDataProviderFunction函数指针方式 - QGIS 3.18+:增加了
ProviderCapability和ProviderMetadataCapability枚举 - QGIS 3.20+:扩展了连接管理功能
六、总结
| 方面 | 说明 |
|---|---|
| 本质 | 数据提供者的元数据容器和工厂类 |
| 主要用途 | 获取提供者信息、创建数据库连接、管理样式 |
| 获取方式 | 通过 QgsProviderRegistry::instance()->providerMetadata(key) |
| 关键方法 | createConnection(), createProvider(), saveConnection() |
| 注意事项 | 异常处理、内存管理、连接字符串格式、线程安全 |
| 典型应用 | 数据库连接测试、图层导入导出、数据源浏览 |
QgsProviderMetadata 是 QGIS 数据访问架构的核心抽象层,理解它对于开发 QGIS 插件或进行底层数据操作至关重要。