- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在从事一项需要多种程序能力的科学项目。在四处寻找可用的工具后,我决定使用 Boost 库,它为我提供了 C++ 标准库不提供的所需功能,例如日期/时间管理等。
我的项目是一组命令行,用于处理来自旧的、自制的、基于纯文本文件的数据库的大量数据:导入、转换、分析、报告。
现在我到了需要坚持的地步。所以我包含了我发现非常有用的 boost::serialization。我能够存储和恢复“中型”数据集(不太大但也不算小),它们大约是 (7000,48,15,10)-数据集。
我还使用 SQLite C API 来存储和管理命令默认值、输出设置和变量元信息(单位、比例、限制)。
我突然想到:序列化到 blob 字段而不是单独的文件。可能有一些我还没有看到的缺点(总是存在),但我认为它可能是一个适合我需要的好解决方案。
我能够将文本序列化为 std::string,所以我可以这样做:没有困难,因为它只使用普通字符。但我想二进制序列化为一个 blob。
在填写 INSERT 查询时,我应该如何处理才能使用标准流?
最佳答案
哈哈。我以前从未使用过 sqlite3 C API。而且我从来没有写过输出 streambuf
执行。但是看到我将来可能会如何在 c++ 代码库中使用 sqlite3,我想我已经花了一些时间
cppreference http://en.cppreference.com/w/cpp/io/basic_streambuf
事实证明你可以 open a blob field for incremental IO .但是,尽管您可以读/写 BLOB,但不能更改大小(除非通过单独的 UPDATE 语句)。
所以,我的演示步骤变成了:
blob_buf
中派生自 std::basic_streambuf<>
的对象并且可以与 std::ostream
一起使用写入那个 blobostream
有效:)
main
中的代码:
int main()
{
sqlite3 *db = NULL;
int rc = sqlite3_open_v2("test.sqlite3", &db, SQLITE_OPEN_READWRITE, NULL);
if (rc != SQLITE_OK) {
std::cerr << "database open failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
// 1. insert a record into a table, binding a "zero-blob" of a certain (fixed) size
sqlite3_int64 inserted = InsertRecord(db);
{
// 2. open the blob field in the newly inserted record
// 3. wrap the blob handle in a custom `blob_buf` object that derives from `std::basic_streambuf<>` and can be used with `std::ostream` to write to that blob
blob_buf buf(OpenBlobByRowId(db, inserted));
std::ostream writer(&buf); // this stream now writes to the blob!
// 4. serialize some data into the `ostream`
auto payload = CanBeSerialized { "hello world", { 1, 2, 3.4, 1e7, -42.42 } };
boost::archive::text_oarchive oa(writer);
oa << payload;
#if 0 // used for testing with larger data
std::ifstream ifs("test.cpp");
writer << ifs.rdbuf();
#endif
// 5. flush
writer.flush();
// 6. destruct/cleanup
}
sqlite3_close(db);
// ==7653== HEAP SUMMARY:
// ==7653== in use at exit: 0 bytes in 0 blocks
// ==7653== total heap usage: 227 allocs, 227 frees, 123,540 bytes allocated
// ==7653==
// ==7653== All heap blocks were freed -- no leaks are possible
}
您会认出概述的步骤。
为了测试它,假设您创建了一个新的 sqlite 数据库:
sqlite3 test.sqlite3 <<< "CREATE TABLE DEMO(ID INTEGER PRIMARY KEY AUTOINCREMENT, FILE BLOB);"
现在,一旦您运行了该程序,您就可以查询它了:
sqlite3 test.sqlite3 <<< "SELECT * FROM DEMO;"
1|22 serialization::archive 10 0 0 11 hello world 5 0 1 2 3.3999999999999999 10000000 -42.420000000000002
如果您启用测试代码(放置比 blob_size 允许的更多的数据),您将看到 blob 被截断:
contents truncated at 256 bytes
#include <sqlite3.h>
#include <string>
#include <iostream>
#include <ostream>
#include <fstream>
#include <boost/serialization/vector.hpp>
#include <boost/archive/text_oarchive.hpp>
template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class basic_blob_buf : public std::basic_streambuf<CharT, TraitsT>
{
sqlite3_blob* _blob; // owned
int max_blob_size;
typedef std::basic_streambuf<CharT, TraitsT> base_type;
enum { BUFSIZE = 10 }; // Block size - tuning?
char buf[BUFSIZE+1/*for the overflow character*/];
size_t cur_offset;
std::ostream debug;
// no copying
basic_blob_buf(basic_blob_buf const&) = delete;
basic_blob_buf& operator= (basic_blob_buf const&) = delete;
public:
basic_blob_buf(sqlite3_blob* blob, int max_size = -1)
: _blob(blob),
max_blob_size(max_size),
buf {0},
cur_offset(0),
// debug(std::cerr.rdbuf()) // or just use `nullptr` to suppress debug output
debug(nullptr)
{
debug.setf(std::ios::unitbuf);
if (max_blob_size == -1) {
max_blob_size = sqlite3_blob_bytes(_blob);
debug << "max_blob_size detected: " << max_blob_size << "\n";
}
this->setp(buf, buf + BUFSIZE);
}
int overflow (int c = base_type::traits_type::eof())
{
auto putpointer = this->pptr();
if (c!=base_type::traits_type::eof())
{
// add the character - even though pptr might be epptr
*putpointer++ = c;
}
if (cur_offset >= size_t(max_blob_size))
return base_type::traits_type::eof(); // signal failure
size_t n = std::distance(this->pbase(), putpointer);
debug << "Overflow " << n << " bytes at " << cur_offset << "\n";
if (cur_offset+n > size_t(max_blob_size))
{
std::cerr << "contents truncated at " << max_blob_size << " bytes\n";
n = size_t(max_blob_size) - cur_offset;
}
if (SQLITE_OK != sqlite3_blob_write(_blob, this->pbase(), n, cur_offset))
{
debug << "sqlite3_blob_write reported an error\n";
return base_type::traits_type::eof(); // signal failure
}
cur_offset += n;
if (this->pptr() > (this->pbase() + n))
{
debug << "pending data has not been written";
return base_type::traits_type::eof(); // signal failure
}
// reset buffer
this->setp(buf, buf + BUFSIZE);
return base_type::traits_type::not_eof(c);
}
int sync()
{
return base_type::traits_type::eof() != overflow();
}
~basic_blob_buf() {
sqlite3_blob_close(_blob);
}
};
typedef basic_blob_buf<char> blob_buf;
struct CanBeSerialized
{
std::string sometext;
std::vector<double> a_vector;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::make_nvp("sometext", sometext);
ar & boost::serialization::make_nvp("a_vector", a_vector);
}
};
#define MAX_BLOB_SIZE 256
sqlite3_int64 InsertRecord(sqlite3* db)
{
sqlite3_stmt *stmt = NULL;
int rc = sqlite3_prepare_v2(db, "INSERT INTO DEMO(ID, FILE) VALUES(NULL, ?)", -1, &stmt, NULL);
if (rc != SQLITE_OK) {
std::cerr << "prepare failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
} else {
rc = sqlite3_bind_zeroblob(stmt, 1, MAX_BLOB_SIZE);
if (rc != SQLITE_OK) {
std::cerr << "bind_zeroblob failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
{
std::cerr << "execution failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
}
rc = sqlite3_finalize(stmt);
if (rc != SQLITE_OK)
{
std::cerr << "finalize stmt failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
return sqlite3_last_insert_rowid(db);
}
sqlite3_blob* OpenBlobByRowId(sqlite3* db, sqlite3_int64 rowid)
{
sqlite3_blob* pBlob = NULL;
int rc = sqlite3_blob_open(db, "main", "DEMO", "FILE", rowid, 1/*rw*/, &pBlob);
if (rc != SQLITE_OK) {
std::cerr << "blob_open failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
return pBlob;
}
int main()
{
sqlite3 *db = NULL;
int rc = sqlite3_open_v2("test.sqlite3", &db, SQLITE_OPEN_READWRITE, NULL);
if (rc != SQLITE_OK) {
std::cerr << "database open failed: " << sqlite3_errmsg(db) << "\n";
exit(255);
}
// 1. insert a record into a table, binding a "zero-blob" of a certain (fixed) size
sqlite3_int64 inserted = InsertRecord(db);
{
// 2. open the blob field in the newly inserted record
// 3. wrap the blob handle in a custom `blob_buf` object that derives from `std::basic_streambuf<>` and can be used with `std::ostream` to write to that blob
blob_buf buf(OpenBlobByRowId(db, inserted));
std::ostream writer(&buf); // this stream now writes to the blob!
// 4. serialize some data into the `ostream`
auto payload = CanBeSerialized { "hello world", { 1, 2, 3.4, 1e7, -42.42 } };
boost::archive::text_oarchive oa(writer);
oa << payload;
#if 0 // used for testing with larger data
std::ifstream ifs("test.cpp");
writer << ifs.rdbuf();
#endif
// 5. flush
writer.flush();
// 6. destruct/cleanup
}
sqlite3_close(db);
}
附言。我一直在处理错误……非常粗鲁。您需要引入一个辅助函数来检查 sqlite3 错误代码并可能将其转换为异常。 :)
关于c++ - 如何将 boost::serialize 成 sqlite::blob?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20409877/
我正在尝试从 Azure 容器中删除 blob。我能够连接到它并列出此问题中代码后面的所有 blob:Upload and Delete Azure Storage Blob using azure-
我正在尝试从 Azure 容器中删除 blob。我能够连接到它并列出此问题中代码后面的所有 blob:Upload and Delete Azure Storage Blob using azure-
运行我的 azure 函数(用于读取 azure blob 存储)后出现错误。 错误是 ID 0dad768d-36d4-4c1a-85ae-2a5122533b3c fail: Func
运行我的 azure 函数(用于读取 azure blob 存储)后出现错误。 错误是 ID 0dad768d-36d4-4c1a-85ae-2a5122533b3c fail: Func
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我没有在网上看到任何有关如何获取位于 BlobContainerClient 内特定目录内的所有 blob 的示例。 以前,我使用的是 Microsoft.Azure.Storage 软件包,但这些软
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我没有在网上看到任何有关如何获取位于 BlobContainerClient 内特定目录内的所有 blob 的示例。 以前,我使用的是 Microsoft.Azure.Storage 软件包,但这些软
我正在编写一些代码,允许用户使用麦克风录制自己的声音,然后将录音上传到 Azure Blob 存储。 为了录制音频,我使用类似于下面的代码 let recordedBlobs = []; this.m
当前使用:https://github.com/Azure/azure-sdk-for-go 概述:我当前正在从 azure blob 存储中下载一个 blob,解析该 blob,然后将转录的 blo
正在观看 this video about how to design Tinder ,在 06:50 提出了关于文件与 BLOBS 的观点。 我想知道大二进制文件和 BLOB(二进制大对象)之间有什
目前我有 hibernate JPA HSQLDB 来自动创建我的数据库表。 如何告诉 JPA 或 Hibernate 将字符串保存为 clob/blob 字段?即一个很长的字符串。到目前为止我找不
我有一个一维 NumPy 数组,其中包含一些“坏”值。我想剔除它们。 每个坏值的邻居只是“顽皮”,但我也想剔除它们。 对不良值的可靠测试是询问: arr<0.1 但是,(我能想到的)对于顽皮值的唯一可
查看有关获取 Blob 和获取 Blob 属性的 MSDN 文档。两个请求看起来相同 "https://myaccount.blob.core.windows.net/mycontainer/mybl
我有 2 个 Blob 存储,一个在 eastus,一个在 canadaeast,我想将一个 .vhd 从 eastus 复制到 canadaeast。我去了 eastus,在我想要复制的 blob
所以场景如下: 我有多个 Web 服务实例,用于将 blob 数据写入 Azure 存储。我需要能够根据收到的时间将 blob 分组到容器(或虚拟目录)中。偶尔(最坏的情况是每天)旧的 blob 会被
在 Azure Blobstorage 中,我有 100 个 Blob,但我只想列出前 10 个 Blob。我该怎么做? 我写的{maxResults:1}没有任何效果,它仍然列出了我所有的 Blob
我们当前的代码使用 Azure SDK 1.8,为了生成共享访问签名,它将首先调用 CloudBlobContainer.GetBlobReference(),然后调用 CloudBlob.GetSh
我有大量文件存储在公共(public) Azure blob 容器中,所有这些文件都通过我的 ASP.NET MVC Web 应用程序中的 HTML 直接引用。例如,blob 存储中一个图像的路径如下
我有一个 NodeJS 后端,它使用 Microsoft 的官方 Blob 存储库 (@azure/storage-blob) 来管理我的 Blob 存储: https://www.npmjs.com
我是一名优秀的程序员,十分优秀!