0

考虑这个非常简单的例子:

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 的回答,因为它内容丰富且方向正确。

4

1 回答 1

0

您的代码泄漏了内存和资源:QFile实例永远不会被破坏,因为您永远不会让事件循环在当前线程中运行,而破坏它们的是事件循环。

没有理由在堆上创建文件对象,也没有任何理由显式关闭文件:QFile是实现 RAII 的正确 C++ 类。销毁它在任何状态下都是安全的,没有资源泄漏。只需销毁文件以关闭其底层句柄。

结合上述建议,代码应为:

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会为你做这件事。因此,上面的代码可以包装在 a 中QObject并移动到专用线程,该线程也应该用于其他事情。

或者,您可以使用线程池并在工作线程中进行读取,但在 GUI 线程中运行计时器。只需将connect上面的语句更改为:

connect(timer, &QTimer::timeout, [reader]{ QtConcurrent::run(reader); });
于 2017-12-05T16:16:13.453 回答