当 windows 屏幕锁定时,new QFile("some.txt") 失败并显示 "device not open"
new QFile("some.txt") fails with "device not open" when windows screen locked
考虑这个非常简单的例子:
for(;;){
QFile *file = new QFile("some.txt");//this is where it fails with "device not open" when windows screen is locked
if(file->exists()){
file->open(QFile::ReadOnly);
QString contents = file->readAll();
file->close();
}
file->deleteLater();
QThread::sleep(2);
}
直到最近 windows 屏幕被锁定时,它仍在继续正常工作,但我不确定它是否开始像这样,因为我开始使用 Qt 5.9 或者它是否是 windows 更新以防止在 windows 屏幕锁定时访问文件。
因此,请提出解决方法或解决方案。
谢谢。
编辑:
事实证明,QFile 或文件访问不是问题,问题在于调用它的位置和调用者。所以我接受@Kuba 的回答,因为它内容丰富且方向正确。
您的代码泄漏了内存和资源:QFile
实例将永远不会被销毁,因为您永远不会让事件循环 运行 在当前线程中,而正是事件循环会销毁它们.
没有理由在堆上创建文件对象,也没有理由显式关闭文件:QFile
是实现 RAII 的正确 C++ class。在任何状态下销毁它都是安全的,不会造成资源泄漏。只需销毁文件即可关闭其底层句柄。
综合以上建议,代码应该是:
for (;;){
QFile file("some.txt");
if (file.exists()){
file.open(QFile::ReadOnly);
auto contents = file->readAll();
qDebug() << "read, n=" << contents.size();
}
QThread::sleep(2);
}
不过,理想情况下,您应该 运行 来自事件循环的代码,而不是阻塞线程。线程是昂贵的资源,拥有一个大部分时间什么也不做的线程是相当浪费的。
auto timer = new QTimer;
timer->start(2000);
auto reader = []{
QFile file("some.txt");
if (file.exists()){
file.open(QFile::ReadOnly);
auto contents = file->readAll();
qDebug() << "read, n=" << contents.size();
}
});
connect(timer, &QTimer::timeout, reader);
要结束读取,请停止或销毁计时器。
该线程应该正在旋转一个事件循环 - QThread::run
的默认实现将为您完成。因此,上面的代码可以包装在 QObject
中并移至专用线程,该线程也应该用于其他事情。
或者,您可以使用线程池并在工作线程中进行读取,但 运行 GUI 线程中的计时器。只有上面的 connect
语句需要更改为:
connect(timer, &QTimer::timeout, [reader]{ QtConcurrent::run(reader); });
考虑这个非常简单的例子:
for(;;){
QFile *file = new QFile("some.txt");//this is where it fails with "device not open" when windows screen is locked
if(file->exists()){
file->open(QFile::ReadOnly);
QString contents = file->readAll();
file->close();
}
file->deleteLater();
QThread::sleep(2);
}
直到最近 windows 屏幕被锁定时,它仍在继续正常工作,但我不确定它是否开始像这样,因为我开始使用 Qt 5.9 或者它是否是 windows 更新以防止在 windows 屏幕锁定时访问文件。
因此,请提出解决方法或解决方案。 谢谢。
编辑: 事实证明,QFile 或文件访问不是问题,问题在于调用它的位置和调用者。所以我接受@Kuba 的回答,因为它内容丰富且方向正确。
您的代码泄漏了内存和资源:QFile
实例将永远不会被销毁,因为您永远不会让事件循环 运行 在当前线程中,而正是事件循环会销毁它们.
没有理由在堆上创建文件对象,也没有理由显式关闭文件:QFile
是实现 RAII 的正确 C++ class。在任何状态下销毁它都是安全的,不会造成资源泄漏。只需销毁文件即可关闭其底层句柄。
综合以上建议,代码应该是:
for (;;){
QFile file("some.txt");
if (file.exists()){
file.open(QFile::ReadOnly);
auto contents = file->readAll();
qDebug() << "read, n=" << contents.size();
}
QThread::sleep(2);
}
不过,理想情况下,您应该 运行 来自事件循环的代码,而不是阻塞线程。线程是昂贵的资源,拥有一个大部分时间什么也不做的线程是相当浪费的。
auto timer = new QTimer;
timer->start(2000);
auto reader = []{
QFile file("some.txt");
if (file.exists()){
file.open(QFile::ReadOnly);
auto contents = file->readAll();
qDebug() << "read, n=" << contents.size();
}
});
connect(timer, &QTimer::timeout, reader);
要结束读取,请停止或销毁计时器。
该线程应该正在旋转一个事件循环 - QThread::run
的默认实现将为您完成。因此,上面的代码可以包装在 QObject
中并移至专用线程,该线程也应该用于其他事情。
或者,您可以使用线程池并在工作线程中进行读取,但 运行 GUI 线程中的计时器。只有上面的 connect
语句需要更改为:
connect(timer, &QTimer::timeout, [reader]{ QtConcurrent::run(reader); });