C++ Qt 临时文件处理的几种方式

C++ Qt 临时文件处理的几种方式

本文主要介绍了 C++ Qt 中临时文件处理的几种方式,包括手动管理、RAII 等方式

💡注意:文中生成的示例代码均为 AI 生成并经过手动修改,仅供参考,实际使用时请根据实际情况进行调整。

1. 手动管理

最为原始的管理方式,手动创建临时文件,使用完再手动删除。足够简单也符合直觉的方式,当代码逻辑足够简单时,可以使用这种方式,一旦代码量增大,逻辑分支增多,不同的分支下可能会忘记删除临时文件,导致临时文件留存,占用磁盘空间。

#include <QFile>
#include <QDir>

void test1()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile file(tempFile);
    if (file.open(QIODevice::WriteOnly))
    {
        file.write("Hello, World!");
        file.close();
    }

    // do something

    file.remove();
}

2. RAII

RAII(Resource Acquisition Is Initialization)是一种编程范式,其核心思想是在对象的构造函数中获取资源,在对象的析构函数中释放资源。这种方式可以保证资源的正确释放,不会因为异常等原因导致资源泄漏。
这里不讨论 RAII 的具体实现,只讨论如何使用 RAII 来管理临时文件的几种方式。

2.1. ScopedGuard

ScopedGuard 是一个简单的 RAII 类,用于管理资源的释放。ScopedGuard 的构造函数接受一个函数指针,当 ScopedGuard 对象析构时,会调用该函数指针。

ScopedGuard 的实现可以做到相当复杂且强大,这里只是一个简单的实现,用于演示如何使用 RAII 来管理临时文件。
C++ 未提供 ScopeGuard 的原生实现,可以使用各种第三方库,如 QScopeGuard 等。

#include <QFile>
#include <QDir>

class ScopedGuard
{
public:
    ScopedGuard(std::function<void()> func) : m_func(func) {}
    ~ScopedGuard() { m_func(); }

private:
    std::function<void()> m_func;
};

void test2()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile file(tempFile);
    if (file.open(QIODevice::WriteOnly))
    {
        file.write("Hello, World!");
        file.close();
    }

    ScopedGuard guard([&]() { file.remove(); }); // remove file when out of scope

    // do something
}

2.2. 智能指针(推荐)

使用智能指针管理临时文件是一种非常好的方式,可以避免手动管理临时文件,也可以避免忘记删除临时文件的问题。

#include <QFile>
#include <QDir>
#include <memory>

class FileDeleter
{
public:
    void operator()(QFile *file) const
    {
        file->remove();
        delete file;
    }
};

void test3()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile *file = new QFile(tempFile);
    if (file->open(QIODevice::WriteOnly))
    {
        file->write("Hello, World!");
        file->close();
    }
    // file will be removed when out of scope
    std::unique_ptr<QFile, FileDeleter> filePtr(file);

    // do something
}

上述代码使用了 std::unique_ptr 来管理临时文件,当 filePtr 对象析构时,会调用 FileDeleteroperator() 方法,从而删除临时文件。
实际上可以看出,FileDeleter 类的实现和 ScopedGuard 类的实现非常类似,只是 FileDeleter 类的 operator() 方法中删除了文件。
如果只是如此,则没有必要将其单独提取出来,直接在 std::unique_ptr 的第二个模板参数中传入一个 lambda 表达式即可。

#include <QFile>
#include <QDir>
#include <memory>

void test4()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile *file = new QFile(tempFile);
    if (file->open(QIODevice::WriteOnly))
    {
        file->write("Hello, World!");
        file->close();
    }

    std::unique_ptr<QFile, std::function<void(QFile *)>> filePtr(file, [](QFile *file) {
        file->remove();
        delete file;
    });
}

通过上述代码,就得到了一个更加简洁的实现方式,这也是将智能指针单独列出来的目的,即提供一种极简的方式,在离开作用域时执行一些操作。

假设一个场景:某个函数的需要对特定数据进行各种检查,不同的检查失败的结果都需要执行统一或类似的操作,这时就可以使用智能指针来管理资源,当检查失败时,直接返回,智能指针会自动释放资源。

#include <QFile>
#include <QDir>
#include <memory>

void test5()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile *file = new QFile(tempFile);
    if (!file->open(QIODevice::WriteOnly))
    {
        delete file;
        return;
    }

    // file will be removed when out of scope
    std::shared_ptr<void> finally(nullptr, [&](void*) { file->remove(); delete file; });

    // do something
}

这里使用了 std::shared_ptr,而不是 std::unique_ptr,因为 std::unique_ptr 必须在构造时传入一个指针,而在目前遇到的部分场景中,可能并不希望传入一个指针,因此使用 std::shared_ptr 更加灵活。

类似的编码范式在其他语言中也有所体现,如 Python 中的 with 语句,Java 中的 try-with-resources 语句,C# 中的 using 语句,Go 中的 defer 语句,Rust 中的 Drop trait 等。

2.3. QScopeGuard(推荐)

💡需要注意的是:Qt 5.12 才引入了这个类

智能指针基于 C++11,不依赖于 Qt,因此可以在任何 C++ 项目中使用。这里再提供类似的,基于 QScopeGuard 的实现方式:

#include <QFile>
#include <QDir>
#include <QScopeGuard>

void test6()
{
    QString tempFile = QDir::tempPath() + "/temp.txt";

    QFile *file = new QFile(tempFile);
    if (!file->open(QIODevice::WriteOnly))
    {
        delete file;
        return;
    }

    // file will be removed when out of scope
    auto cleanup = qScopeGuard([file] { file->remove(); delete file; });

    // do something
}

可以看到,相比于 std::shared_ptrQScopeGuard 的使用更加简洁友好一些,但是需要依赖 Qt。

2.4. QTemporaryFile(推荐)

QTemporaryFile 是 Qt 提供的一个临时文件类,用于创建临时文件,当 QTemporaryFile 对象析构时,会自动删除临时文件。

实际应用场景:需要调用一个函数向临时文件中写入数据,后续又需要调用另一个函数对该临时文件进行加密。这时就可以使用 QTemporaryFile 来管理临时文件。

#include <QTemporaryFile>

void createFile(const QString &fileName)
{
    // do something
    writeSomethingToFile(fileName);
    // do something
}

void encryptFile(const QString &fileName)
{
    // do something
    encryptFile(fileName);
    // do something
}

void test7()
{
    QTemporaryFile file;
    if (file.open())
    {
        createFile(file.fileName());
    }

    encryptFile(file.fileName());

    // do something

}

使用 QTemporaryFile 的另一个好处是,不需要关心文件的命名规则、文件名是否重复、文件的路径等问题。在上述代码中,只要 QTemporaryFile 对象open成功,就可以直接使用 fileName 来获取自动生成的临时文件绝对路径。

总结

  1. 当你不关心文件的命名规则、文件名是否重复、文件的路径等问题时,使用 QTemporaryFile
  2. 当你需要在离开作用域时执行一些操作时,使用智能指针(std::shared_ptr<void> finally(nullptr, [&](void*) { /* do something */ });
  3. 当代码逻辑足够简单时,直接手动管理临时文件即可
  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值