如何检查 QImage::save() 是否已完成写入磁盘?

How to check that QImage::save() has finished writing to disk?

我有一个程序,现在可以将 18 兆像素或更小的大图像保存到磁盘。在我将它们转换为 QImage 的过程中,在 QDialog 的子 class 中显示 QImage,然后提示用户保存它们。

我想为用户提供某种进度指示器,所以我推断实现该目标的最佳方法是创建一个 QThread,在线程中使用一个 worker 保存图像,然后发出一个向 GUI 发出信号以声明保存已完成。我使用这个方法在保存过程中向用户显示一个进度条。

在这里考虑这个简单的工人 class:

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QImage &image, const QString &file) {

        if(image.save(file, "PNG", 100))
            emit resultReady();
        else
        {
            // handle error
            return;
        }
    }

signals:
    void resultReady();
};

我的问题是 image::save() 函数 returns true 通常在图像实际完成写入磁盘之前很久。使用当前这行代码,在我的 5600 HDD 上,resultReady() 信号在用户按下按钮后大约 6 秒触发,因此我的 GUI 更新以显示图像已完成保存。

但是,QImage 似乎需要 7 秒到 30 秒才能完成写入磁盘。在此期间,用户可能已经结束了应用程序,这会导致磁盘上的映像不完整,因为线程认为自己已完成。也许更糟糕的是,用户可能会继续拍摄多张其他图像,这些图像开始加剧保存图像所花费的时间。

有没有办法准确确定 Qt 应用程序何时完成将 QImage 写入硬盘?

无论如何,在主线程中处理如此大的数据不是一个好主意。对于此类问题,Qt 框架提供了很好的工具。在 Qt 文档中查找 QConcurrent。 在您的情况下,我会使用 Concurrent 运行 来保存文件,使用 QFutureWatcher 检索进度条的数据。

您对问题的诊断不正确。一旦 image.save 返回,文件系统处于一致状态,此时您可以强行退出应用程序:文件将具有正确的内容。 on-disk 状态是否一致是未知的,但这意味着您不应该重置或强行关闭机器。不过,您的应用程序可以自由退出。

你的问题是另外一回事。谁知道呢:你没有提供测试用例。

不需要手动处理工作线程和对象。杠杆 QtConcurrent。这应该很容易,而且确实如此。即:

class MyWindow : public QWidget {
  Q_OBJECT
  CountDownLatch m_latch;
  Q_SIGNAL void imageSaved(const QString & filename);
  Q_SIGNAL void imageSaveFailed(const QString & filename);
  void saveImage(const QImage & image, const QString & filename) {
    auto lock = m_latch.lock();
    QtConcurrent::run([=]{ // captures this, lock, image and filename
      if (image.save(filename, "PNG", 100))
        emit imageSaved(filename);
      else
        emit imageSaveFailed(filename);
    });
  }
  ...
  // MyWindow's destructor will block until all image savers are done
};

有关 CountDownLatch 的实施,请参阅 this question

@Ketta:你如何重现同样的行为?也许硬盘缓冲或其他原因是原因。对于您的问题,我更喜欢提供更多控制的更详细的方法。也许

    QImage image;
    QFile file("file.png");
    file.open(QIODevice::WriteOnly);
    QDataStream out(&file);         
    image.save(&file, "PNG");  

这可能会为您提供更多的可能性来控制数据的写入。 @库巴:

     connect( &m_futureWatcher, SIGNAL ( finished(  ) ),  this, SLOT( showText  (  )) );

…… 和

      m_futureFileReader = QtConcurrent::run(readFile, pIODevice );        
      m_futureWatcher.setFuture(m_futureFileReader);

作为阅读文本文件的示例,我觉得它并不笨重。