如何检查 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);
作为阅读文本文件的示例,我觉得它并不笨重。
我有一个程序,现在可以将 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);
作为阅读文本文件的示例,我觉得它并不笨重。