当 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); });