【问题标题】:How to create blob stream using unique_ptr?如何使用 unique_ptr 创建 blob 流?
【发布时间】:2021-07-06 23:40:43
【问题描述】:

使用以下代码时,我成功地将图像保存到“图像”blob 字段中:

if (OpenDialog1->Execute()) {
    ADOTable1->Insert();
    TStream* BlobStream = ADOTable1->CreateBlobStream(ADOTable1->FieldByName("Image"), bmWrite);
    std::unique_ptr<TFileStream> FileStream(new TFileStream(OpenDialog1->FileName, fmOpenRead));
    BlobStream->CopyFrom(FileStream.get(), FileStream->Size);
    delete BlobStream;
    ADOTable1->Post();
}

但是,我也想使用std:unique_ptr 创建BlobStream 对象,这样我就可以避免手动delete。当我尝试时

if (OpenDialog1->Execute()) {
    ADOTable1->Insert();
    std::unique_ptr<TStream> BlobStream(ADOTable1->CreateBlobStream(ADOTable1->FieldByName("Image"), bmWrite));
    std::unique_ptr<TFileStream> FileStream(new TFileStream(OpenDialog1->FileName, fmOpenRead));
    BlobStream->CopyFrom(FileStream.get(), FileStream->Size);
    ADOTable1->Post();
}

我得到 无法插入空行错误。我在这里做错了什么?我正在使用 C++ Builder 10.3.3。

【问题讨论】:

    标签: c++ blob c++builder


    【解决方案1】:

    在原始代码中,您在调用Post() 之前之前是delete'ing blob TStream 对象。

    根据TADOBlobStream 文档:

    http://docwiki.embarcadero.com/Libraries/en/Data.Win.ADODB.TADOBlobStream.Destroy

    Destroy [即析构函数] 执行以下任务:

    • 设置字段的数据。

    • 将字段对象的 Modified 属性更改为 true。

    • 在字段的数据集对象中触发字段更改事件。

    • 调用继承的析构函数。

    因此,您在 Post()'ing 之前设置了 blob 的字段数据,一切都很好。

    在更新后的代码中,当BlobStream 超出范围调用Post() 时,您是delete'ing blob TStream 对象。因此,尚未设置字段数据,因此出现错误。

    为确保 blob TStream 对象在调用 Post() 之前被破坏,您可以:

    • BlobStream 周围添加一个新范围:
    if (OpenDialog1->Execute()) {
        std::unique_ptr<TFileStream> FileStream(new TFileStream(OpenDialog1->FileName, fmOpenRead));
        ADOTable1->Insert();
        {
        std::unique_ptr<TStream> BlobStream(ADOTable1->CreateBlobStream(ADOTable1->FieldByName("Image"), bmWrite));
        BlobStream->CopyFrom(FileStream.get(), FileStream->Size);
        }
        ADOTable1->Post();
    }
    
    if (OpenDialog1->Execute()) {
        std::unique_ptr<TFileStream> FileStream(new TFileStream(OpenDialog1->FileName, fmOpenRead));
        ADOTable1->Insert();
        std::unique_ptr<TStream> BlobStream(ADOTable1->CreateBlobStream(ADOTable1->FieldByName("Image"), bmWrite));
        BlobStream->CopyFrom(FileStream.get(), FileStream->Size);
        BlobStream.reset();
        ADOTable1->Post();
    }
    

    无论哪种方式,如果在 Post()'ed 之前发生意外情况,您应该对新行插入进行一些错误处理,以便 Cancel() 插入新行,例如:

    if (OpenDialog1->Execute()) {
        std::unique_ptr<TFileStream> FileStream(new TFileStream(OpenDialog1->FileName, fmOpenRead));
        ADOTable1->Insert();
        try {
            std::unique_ptr<TStream> BlobStream(ADOTable1->CreateBlobStream(ADOTable1->FieldByName("Image"), bmWrite));
            BlobStream->CopyFrom(FileStream.get(), FileStream->Size);
            BlobStream.reset();
            ADOTable1->Post();
        }
        catch (const Exception &) {
            ADOTable1->Cancel();
            throw;
        }
    }
    

    【讨论】:

    • 啊,我看到更新的内容和“销毁”实际上是“设置字段数据”的声明。现在它为什么不起作用是有道理的。尽管如此,这对我来说还是不合逻辑的。
    • @Tracer 好吧,毕竟它是一个流。您可以多次写入它。它需要知道您何时完成对其的写入。如果这不是由析构函数处理的,则需要显式调用方法,例如:BlobStream = ...; BlobStream-&gt;Write(...); BlobStream-&gt;CommitModifiedData(); ADOTable1-&gt;Post(); delete BlobStream; 一旦提交,流就不能再使用了。所以析构函数更有意义。
    • 就个人而言,我更喜欢一些显式的方法来设置 blob 字段的值。这是非常具体的,我从未见过有人以这种方式使用析构函数,并且除了“清理”对象之外的任何其他事情。我希望他们能实现像 ADOTable1-&gt;FieldByName("Image")-&gt;LoadFromStream(...)AsStream 等这样的东西,这些东西将在 blob/binary 类型的字段上得到支持。
    • @Tracer "我希望他们能实现 ADOTable1-&gt;FieldByName("Image")-&gt;LoadFromStream(...)" ——他们确实做到了。 TBlobField 有一个公共的LoadFromStream 方法,例如:static_cast&lt;TBlobField*&gt;(ADOTable1-&gt;FieldByName("Image"))-&gt;LoadFromStream(...);
    • 太棒了!现在这也有效:dynamic_cast&lt;TBlobField*&gt; (ADOTable1-&gt;FieldByName("Image"))-&gt;LoadFromStream(FileStream.get());
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2017-03-14
    • 2013-06-23
    • 2021-09-08
    相关资源
    最近更新 更多