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

时间:2016-07-13 14:00:17

标签: c++ multithreading qt qthread qimage

我有一个程序,我现在正在将大的,1800万像素或更少的图像保存到磁盘上。一路上我将它们转换为QImage,在QDialog的子类中显示QImage,然后提示用户保存它们。

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

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

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()函数经常在图像实际写入磁盘之前很久就返回true。使用当前的代码行,在我的5600 HDD上,resultReady()信号在用户按下按钮后大约6秒被触发,因此我的GUI更新以显示图像已完成保存。

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

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

3 个答案:

答案 0 :(得分:2)

您对此问题的诊断不正确。一旦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

答案 1 :(得分:0)

无论如何,处理主线程中的大数据是一个坏主意。对于这些问题,Qt框架提供了很好的工具。查看QConcurrent的Qt文档。 在您的情况下,我将使用 Concurrent Run 保存文件,以使用QFutureWatcher检索进度条的数据。

答案 2 :(得分:0)

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

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

这可能为您提供控制数据写入的能力。 @Kuba:

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

...... 和

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

作为阅读文本文件的一个例子对我来说似乎并不笨重。