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



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

我想为用户提供某种进度指示器,因此我推断我实现这一目标的最佳方法是创建一个 QThread,使用线程内的工作线程保存图像,然后向 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写入硬盘?

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

你的问题是另一回事。谁知道呢:您未能提供测试用例。

无需手动处理工作线程和对象。杠杆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的实现,请参阅此问题。

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

@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);

作为阅读文本文件的示例,对我来说似乎不是很笨重。

最新更新