我在运行Qt程序的测试安装时遇到了一些奇怪的行为(尝试使用qt 5.5.1和7.0)。我在调试/开发环境中运行时没有注意到这个问题 - 但是在安装到“Program Files(x86)”时会看到问题。
问题是:我正在使用QDirIterator在“QStandardPaths :: DataLocation”位置查找数据库文件并通过sqlite加载它们。幻像文件位于程序文件(x86)// Library / .ndat中我看到的是先前安装的文件(已被删除)以及已重命名,然后删除的文件仍然显示并且是在程序中可读。这些“幻像”文件阻止加载最新文件。这真的很奇怪 - 我想知道是否有人见过这个问题?
我在基于SSD的计算机上运行Windows 10 Home(如果重要的话)。与Qt 5.5.1和5.7相同的问题。我已经在具有类似配置的不同机器上复制了它。
有什么想法吗?
以下是我的代码摘要:
QStringList standardPaths = QStandardPaths::locateAll(QStandardPaths::DataLocation, "Library", QStandardPaths::LocateDirectory);
QStringList fileFilters;
fileFilters << "*.ndat";
foreach (const QString &dir, standardPaths) {
QDirIterator iterator (dir, fileFilters);
while (iterator.hasNext()) {
const QString &filePath = iterator.next();
QString databaseName = QFileInfo(filePath).baseName();
database_->open(filePath, baseName); // my function
}
}
boolDataManager::open (const QString &filePath, const QString &connectionName) {
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
db.setDatabaseName (filePath);
if (!db.open()) {
ERROR(QString("Cannot open database %1 with error %2")
.arg(QFileInfo(filePath).baseName())
.arg(db.lastError().text()));
printError();
return false;
}
databaseNames_.append(connectionName);
return true;
}
此代码似乎在不再存在的文件中读取 - 奇怪的是,读取已在同一位置覆盖的旧文件的内容。只有当文件位于“Program Files”目录中时才会发生这种情况;不在用户目录或什么不是。
例如,我的代码的第1版有一个名为“database.dat”的数据库,有10个条目。我的安装版本2用一个具有20个条目的同名文件覆盖了该文件。我的代码的第2版找到了database.dat文件,但只读取了10个条目的旧版本 - 真的很奇怪!
更新
这些“幻像”文件似乎存储在: C:\ Users / USERNAME / AppData / Local / VirtualStore / Program Files(x86)/ PROGRAM NAME / database.dat
我的猜测是我在我的程序中打开文件而不是只读,因此Windows在用户可写的位置创建了一个工作副本。将调查。
答案 0 :(得分:1)
问题是Windows缓存 - 我认为 - 一个人无法告诉软件没有提供任何调试方法 - 例如Windows。
我听说通过打开“应用程序体验”服务也可以解决(或者至少减少)这个解决方案 - 我仍然不时地遇到它,通常是在进行过多的文件系统写入时没时间了。
我不确切知道原因是什么 - 而且我很确定没有其他人做过或者它会被修复......但据我所知,没有解决方法(截至此答案的日期)< / p>
-
以下是我对这类问题的解决方案,它可以100%的时间运行:
要避免此问题,请在每次编译时将版本号附加到数据库文件名的末尾,实际上使用
将其添加到所有文件中#define VERSION 4.22.21
然后只添加.append(QString("%1").arg(VERSION));
或其他内容。
然后你要做的就是编写一些快速代码来从旧数据库或从任何地方导入所有必要的数据,不管怎样,你应该或多或少地使用数据库。
最好避免这样的情况,而不是尝试解决它们 - 更不用说你现在有一个完美的修订系统,甚至没有尝试。
<强>更新强>
由于没有用例,没有代码,也没有关于项目的信息,我不得不猜测你想要做什么 -
QList<DataDir*> dataDirectories;
DataDir* new_dataDir;
QStringList standardPaths = QStandardPaths::locateAll(QStandardPaths::DataLocation, "Library", QStandardPaths::LocateDirectory);
QStringList fileFilters;
fileFilters << "*.ndat";
foreach (const QString &dir, standardPaths) {
QDirIterator iterator (dir, fileFilters);
while (iterator.hasNext()) {
const QString &filePath = iterator.next();
QString databaseName = QFileInfo(filePath).baseName();
database_->open(filePath, baseName); // my function
/* Do your database reading or writing and save the results
* into a QHash or something then do this: */
database_->close(); // super important
}
}
答案 1 :(得分:0)
经过一番探索之后,我找到了问题的根源(和解决方案)。
Windows(为了向后兼容)具有VirtualStore功能,如果程序尝试写入不可写的文件(基于权限,例如Program Files / Progname / test.txt),它会将该文件复制到USER / AppData / Local / VirtualStore / Program Files / ....卸载程序时不会删除此新文件,但会将QT程序视为位于其原始位置。
解决方案是以只读模式打开Sqlite数据库:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
if (!writable_)
db.setConnectOptions(QLatin1String("QSQLITE_OPEN_READONLY"));
db.setDatabaseName (filePath);
现在,我遇到了确定文件是否可写的问题。这样:
writable_ = fInfo.isWritable();
总是返回true,即使对于Program Files中的文件也是如此。即使启用NTFS权限检查:
extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;
qt_ntfs_permission_lookup++; // turn permisssions checking on
权限检查不起作用。所以现在我只是这样做:
QString appDir = gApp->applicationDirPath();
QString relFilepath = QDir(appDir).relativeFilePath(filePath);
if (!relFilepath.startsWith(".."))
writable_ = false;
数据库是只读的(我的应用程序没问题),不再在VirtualStore中创建任何内容