如何将从文件读取的char*以vector<byte>形式插入SQLite数据库
我来帮你搞定这个需求!要把文件内容以二进制字节数组的形式存入SQLite,既安全又能避免明文查看,咱们一步步来:
1. 完善文件读取逻辑并转换为
vector<byte> 首先补全你未完成的文件读取代码,同时直接将读取的char*缓冲区转换为vector<byte>(这里用uint8_t作为byte的底层类型,和SQLite的BLOB类型完美匹配),还能避免手动管理内存的风险:
#include <fstream> #include <vector> #include <cstdint> #include <iostream> #include <string> // 定义byte类型,和SQLite的BLOB存储对应 using byte = uint8_t; class DataBaseUtils { public: void readFileContents(const std::string& filePath, std::vector<byte>& outBytes) { std::ifstream file(filePath, std::ios::binary); if (!file.is_open()) { std::cerr << "Failed to open file: " << filePath << "\n"; return; } // 获取文件总大小 file.seekg(0, std::ios::end); std::streampos fileSize = file.tellg(); file.seekg(0, std::ios::beg); // 初始化vector并直接读取文件内容到vector的内存中 outBytes.resize(static_cast<size_t>(fileSize)); file.read(reinterpret_cast<char*>(outBytes.data()), fileSize); // 校验读取是否完整 if (!file) { std::cerr << "Failed to read entire file: " << filePath << "\n"; outBytes.clear(); } } };
2. 将
vector<byte>插入SQLite数据库 SQLite原生支持BLOB类型存储二进制数据,咱们用预处理语句来插入,既能安全处理二进制中的特殊字符(比如NULL字节),又能避免SQL注入,同时确保数据以二进制形式存储(而非明文文本)。
第一步:先创建带BLOB字段的表
如果还没建表,先执行这条SQL创建存储结构:
CREATE TABLE IF NOT EXISTS file_storage ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_content BLOB NOT NULL, file_name TEXT NOT NULL );
第二步:C++插入代码实现
#include <sqlite3.h> class DataBaseUtils { // ... 前面的readFileContents方法 ... public: bool insertBlobIntoDB(const std::string& dbPath, const std::vector<byte>& fileBytes, const std::string& fileName) { sqlite3* db; int rc = sqlite3_open(dbPath.c_str(), &db); if (rc != SQLITE_OK) { std::cerr << "Cannot open database: " << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return false; } // 预处理插入语句,用?作为占位符 const char* insertSql = "INSERT INTO file_storage (file_content, file_name) VALUES (?, ?);"; sqlite3_stmt* stmt; rc = sqlite3_prepare_v2(db, insertSql, -1, &stmt, nullptr); if (rc != SQLITE_OK) { std::cerr << "Failed to prepare statement: " << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); return false; } // 绑定BLOB数据:占位符索引从1开始,直接传入vector的原始字节和长度 rc = sqlite3_bind_blob(stmt, 1, fileBytes.data(), static_cast<int>(fileBytes.size()), SQLITE_STATIC); if (rc != SQLITE_OK) { std::cerr << "Failed to bind BLOB data: " << sqlite3_errmsg(db) << "\n"; sqlite3_finalize(stmt); sqlite3_close(db); return false; } // 绑定文件名(文本类型) rc = sqlite3_bind_text(stmt, 2, fileName.c_str(), -1, SQLITE_TRANSIENT); if (rc != SQLITE_OK) { std::cerr << "Failed to bind file name: " << sqlite3_errmsg(db) << "\n"; sqlite3_finalize(stmt); sqlite3_close(db); return false; } // 执行插入操作 rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { std::cerr << "Failed to execute insert: " << sqlite3_errmsg(db) << "\n"; sqlite3_finalize(stmt); sqlite3_close(db); return false; } // 清理资源 sqlite3_finalize(stmt); sqlite3_close(db); return true; } };
关键细节说明:
sqlite3_bind_blob会告诉SQLite把数据当成二进制存储,不会做任何文本解析,所以直接查看数据库文件时看不到明文内容。SQLITE_STATIC表示SQLite不需要负责释放数据内存(因为vector<byte>在语句执行期间会保持有效);如果数据是动态分配的,可以用SQLITE_TRANSIENT让SQLite复制一份数据。
3. 调用示例
int main() { DataBaseUtils utils; std::vector<byte> fileBytes; // 读取文件内容到vector<byte> utils.readFileContents("/path/to/your/target/file", fileBytes); // 插入到SQLite数据库 if (!fileBytes.empty()) { bool success = utils.insertBlobIntoDB("my_database.db", fileBytes, "target_file_name"); if (success) { std::cout << "File content inserted as binary successfully!\n"; } } return 0; }
内容的提问来源于stack exchange,提问作者Deenadayalan S
相关产品推荐
相关产品推荐

