跳转到内容
新建笔记

Qt 文件校验:模型路径、实际打开与加载状态

用户在输入框里选择 .engine 或 .trt 文件时,路径检查可以提前发现空输入、目录、错误后缀和打不开的文件。它不能证明文件内容是有效推理引擎,也不能代替后续加载器对格式、版本和运行环境的检查。

原来的流程直接 new YOLO(...),再通过 modelState 显示成功。重复加载时,这容易遗漏旧对象释放和失败后的状态重置。应先定义状态与所有权,再将文件检查和实际引擎加载分开。

阶段可以确认什么仍需处理的事情
路径与元数据检查输入非空、当前存在、指向普通文件、后缀符合策略文件可能在随后发生变化
尝试打开当前进程此时能够以指定模式打开内容可能为空、损坏或不受支持
引擎加载由实际加载器确认格式与兼容性失败原因、资源释放和界面状态

QFileInfo::suffix() 返回最后一个点后面的后缀。下面显式采用后缀大小写不敏感的产品规则,因此 MODEL.ENGINE 可以通过;这与文件系统查找路径时的大小写规则是两回事。QFileInfo 后缀

检查与打开之间可能有变化,exists() 或 isReadable() 的结果也不能保证下一次打开成功。实际执行 QFile::open() 并处理错误;实际加载器重新打开同一路径时,仍必须处理它自己的失败。QFile 打开文件

完整例子:检查器与临时文件

跳转到“完整例子:检查器与临时文件”

这段程序只验证文件选择条件,依赖 Qt 6 的 Qt6::Core 和 C++17。以开启断言的 Debug 配置运行测试。测试文件故意只是普通文字,用于证明“通过路径检查”不等于“引擎加载成功”。这里不依赖或伪造 YOLO 的接口。

#include <QByteArray>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QString>
#include <QTemporaryDir>
#include <cassert>
enum class FileIssue { None, EmptyPath, NotFound, NotFile, WrongSuffix, CannotOpen };
struct FileCheck {
FileIssue issue;
QString absolutePath;
QString detail;
bool accepted() const { return issue == FileIssue::None; }
};
FileCheck checkEngineFile(const QString& input) {
// 这里保留用户选中的文件名,不擅自删除有意义的前后空格。
if (input.isEmpty())
return {FileIssue::EmptyPath, {}, QStringLiteral("请选择模型文件")};
const QFileInfo info(input);
if (!info.exists())
return {FileIssue::NotFound, {}, QStringLiteral("文件不存在")};
if (!info.isFile())
return {FileIssue::NotFile, {}, QStringLiteral("请选择文件而非目录")};
const QString suffix = info.suffix().toLower();
if (suffix != "engine" && suffix != "trt")
return {FileIssue::WrongSuffix, {}, QStringLiteral("需要 .engine 或 .trt 文件")};
const QString absolutePath = info.absoluteFilePath();
QFile file(absolutePath);
if (!file.open(QIODevice::ReadOnly))
return {FileIssue::CannotOpen, {}, file.errorString()};
return {FileIssue::None, absolutePath, {}};
}
void writeFixture(const QString& path) {
QFile file(path);
assert(file.open(QIODevice::WriteOnly));
const QByteArray data("not a real inference engine");
assert(file.write(data) == data.size());
assert(file.flush());
}
int main() {
QTemporaryDir directory;
assert(directory.isValid());
const QDir root(directory.path());
const QString model = root.filePath("model.engine");
const QString uppercase = root.filePath("MODEL.ENGINE");
const QString trt = root.filePath("model.trt");
const QString wrong = root.filePath("model.txt");
writeFixture(model);
writeFixture(uppercase);
writeFixture(trt);
writeFixture(wrong);
assert(root.mkdir("folder.engine"));
assert(checkEngineFile({}).issue == FileIssue::EmptyPath);
assert(checkEngineFile(root.filePath("missing.engine")).issue == FileIssue::NotFound);
assert(checkEngineFile(root.filePath("folder.engine")).issue == FileIssue::NotFile);
assert(checkEngineFile(wrong).issue == FileIssue::WrongSuffix);
const FileCheck result = checkEngineFile(model);
assert(result.accepted() && QFileInfo(result.absolutePath).isAbsolute());
assert(checkEngineFile(uppercase).accepted());
assert(checkEngineFile(trt).accepted());
assert(QFile::remove(model));
assert(checkEngineFile(model).issue == FileIssue::NotFound);
}

程序覆盖真实临时文件、大小写后缀、目录伪装、删除后重查和缺失路径。打开失败分支保留实际错误信息,但没有用这个测试声称所有操作系统权限失败都已覆盖。

每次点击加载,先进入“正在加载”状态,禁用依赖该模型的操作,并清理上一次错误。检查不通过时在 QTextBrowser 等控件显示原因;检查通过后再显示 Loading engine file... 并调用实际加载器。

只有加载器明确返回有效模型,才显示成功并启用相关功能。失败时要保持禁用状态,不能沿用上次成功留下的布尔值。模型由 RAII 所有者管理,例如合适删除器的智能指针;加载新模型采用临时所有者,成功后再替换原对象。如果业务选择“失败时继续使用旧模型”,界面必须明确显示仍在使用旧模型,而不是显示新模型加载成功。

原例中的 modelFilePath.toStdString() 也需要结合加载器要求:Qt 的字符串表示、UTF-8 字节路径和 Windows 宽字符文件接口不能混为一谈。保持 QString 到适配边界,再按真实引擎 API 转换。耗时加载则应按引擎线程约束安排后台工作,并让界面更新回到 GUI 线程。