2016-11-05 84 views
0

我看到一些奇怪的行为,当我的Qt程序(尝试使用qt 5.5.1和7.0)的测试安装运行。在调试/开发环境中运行时,我没有注意到这个问题 - 但在安装到“Program Files(x86)”中时看到问题。Qt加载删除/重命名文件与Windows 10

问题是:我正在使用QDirIterator查找“QStandardPaths :: DataLocation”位置内的数据库文件并通过sqlite加载它们。幻影文件位于Program Files(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:\用户/用户名/应用程序数据/本地/ VirtualStore /程序文件(x86)/节目名称/ database.dat

我的猜测是,我打开我的程序中的文件不是只读,所以Windows在用户可写的位置创建一个工作副本。将调查。

+0

也许您的数据库存储的旧文件名或什么造成什么吗?你可以请发布完整的代码,以便我们可以了解发生了什么。 – mike510a

+0

“整个”代码是专有的,但让我们看看我是否可以澄清(参见上文) – Mikes

+0

顺便说一下,您可能不应该每次打开数据库 - 您可以打开一次,然后多次写入它 – mike510a

回答

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

1

问题是Windows缓存 - 我认为 - 一个不能提供任何方式来调试它的软件 - 例如Windows。

我听说这个解决方案也可以通过打开“应用程序体验”服务来解决(或者至少减少) - 我仍然经常遇到它,通常是在执行过多的文件系统写入时时间太短了。

我不知道究竟是什么原因 - 我很确定没有其他人做,或者它会被修复..但据我所知是没有修复该(因为这答案的日期)

-

这里是我的解决方案,像这样的工作时间的100%的问题:

为了避免这个问题,追加的版本号在每次编译的时候你的数据库的文件名的末尾,实际上它apppend到您的所有文件通过使用

#define VERSION 4.22.21 

,然后就加入.append(QString("%1").arg(VERSION));什么的。

所有你真正要做的事情是编写一些快速代码来从旧数据库或从任何地方导入所有必要的数据,这些数据应该或多或少地来自使用数据库。

更好地避免这种情况,而不是试图找出它们 - 更不用说你现在有一个完美的修改系统,甚至没有尝试。

UPDATE

因为世界上没有使用的情况下,没有代码,并没有关于该项目的信息,我会在你试图做猜测 -

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 


    } 
} 
+0

我很高兴我不是唯一见过它的人 - 你见过其他任何网页吗?我希望有一个更好/不同的答案,因为改变文件名每个rev是不是我要找的。我可能会将这些文件转移到用户AppData中。 – Mikes

+0

我的确读过一个非常类似的问题 - 但我认为你的特殊情况与你使用QDirIterator和数据库的方式有关。虐待添加一些更多的信息给我的答案... – mike510a

+0

这是一个特定的测试我创建的情况下,它突出了错误:1)将database.dat复制到同一目录下的test.dat 2)运行程序(程序读取两个文件)3)删除test.dat,清空回收站4)重新运行程序,仍然注册并且可以被读取。 – Mikes