【问题标题】:VC++ Store array<unsigned char>^ in MySql databaseVC++ 在 MySql 数据库中存储数组<unsigned char>^
【发布时间】:2017-01-28 00:12:14
【问题描述】:

我正在开发一个 VC++ cli 应用程序,我需要将图像存储到 MySql 数据库中。我意识到这通常不是一个好的做法,但由于对文件系统的访问受限,这是我必须走的路。

所以我已经能够将图像放入一个托管的 unsigned char 数组中,这看起来就像我在网上找到的示例中必须做的(这些示例大多在 C# 中并且包含不可用的命令)。我只需要弄清楚如何将其输入数据库,我不知所措,而且我的搜索至少没有发现任何对 VC++ 有用的东西。

这是我需要做的,我有一个托管数组:

array<unsigned char>^ imageSource;

包含图像的字节,使用:

System::IO::FileStream^ fs;
System::IO::BinaryReader^ br;

//Read the Image
fs = gcnew System::IO::FileStream(filepath, System::IO::FileMode::Open, System::IO::FileAccess::Read);
br = gcnew System::IO::BinaryReader(fs);

//Store the Image into an array
imageSource = br->ReadBytes((int)fs->Length);

接下来我需要将它保存到我的数据库中:

sql::Connection *sqlConn;
sql::PreparedStatement *sqlStmt;
sql::ResultSet *sqlResult;

// Sql Connection Code

//I have a Routine to save images 
//and have Select because get_last_insert_id() is not available in the c++ connector
sqlStr = "SELECT save_item_image (?, ?, ?, ?, ?) AS ID";

//Prepare the Query
sqlStmt = this->sqlConn->prepareStatement(sqlStr);

//Set Parameters in SqlStatment
sqlStmt->setInt(1, 1);
sqlStmt->setInt(2, 1);
sqlStmt->setBlob(3, &imgSource); <-- This is where I need to insert image
sqlStmt->setString(4, "jpg");
sqlStmt->setString(5, "test.jpg");
sqlStmt->executeUpdate();

据我了解,setBlob 函数需要 std::istream 来读取数据。我不知道该怎么做,这是我的主要问题。

【问题讨论】:

  • 嗯我还是不明白为什么你选择而不是插入...
  • @KonstantinosKamaropoulos 这是一个插入函数,我必须使用 SELECT 才能获取插入的 id,因为 C++ 连接器不像其他语言那样具有 last_insert_id()。跨度>
  • 哦,所以你正在插入并获取你的行得到的 id?
  • @KonstantinosKamaropoulos 是的。我几乎将托管数组放入 istream 中,这就是问题所在。
  • 为什么首先要使用无符号字符数组?

标签: mysql image visual-c++ c++-cli


【解决方案1】:

我终于想通了,想发布一个答案,以防其他人正在寻找这个答案。

最简单的方法是使用 pin_ptr 来引用托管数组中的第一个元素,该元素实际上是指向整个数组的指针。接下来我们转换为另一个指针,最后转换为 char* 指针。最后为了在 setBlob 中使用它,我们需要为 istream 创建一个内存缓冲区。

这是一个工作示例:

将图像文件读入托管数组:

array<unsigned char>^ rawImageData;
System::IO::FileStream^ fs;
System::IO::BinaryReader^ br;

//Setup the filestream and binary reader
fs = gcnew System::IO::FileStream(filepath, System::IO::FileMode::Open, System::IO::FileAccess::Read);
br = gcnew System::IO::BinaryReader(fs);

//Store the Image into a byte array
rawImageData = br->ReadBytes((int)fs->Length);

内存缓冲区

#include <iostream>
#include <istream>
#include <streambuf>
#include <string>

struct membuf : std::streambuf {
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};

最后是 MySQL 代码:

sql::Driver *sqlDriver;             
sql::Connection *sqlConn;           
sql::PreparedStatement *sqlStmt;
sql::ResultSet *sqlResult;

/*** SQL Connection Code Here ***/

//Build the Item Sql String to Save Images
sqlStr = "SELECT save_item_image (?, ?, ?, ?, ?) AS ID";

//Prepare the Query
sqlStmt = sqlConn->prepareStatement(sqlStr);

//Create a pin_ptr to the first element in the managed array
pin_ptr<unsigned char> p = &rawImageData[0];

//Get a char pointer to use in the memory buffer
unsigned char* pby = p;
char* pch = reinterpret_cast<char*>(pby);

//Memory Buffer, note the use of length from the RawImageData, images contain
//NULL char's so size_of doesn't return the right length.
membuf sbuf(pch, pch + rawImageData->Length);

//Create the istream to use in the setBlob
std::istream sb(&sbuf, std::ios::binary | std::ios::out);

//Finally save everything into the database
sqlStmt->setInt(1, 1);
sqlStmt->setInt(2, 1);
sqlStmt->setBlob(3, &sb);   //*** Insert the Image ***/
sqlStmt->setString(4, "Name");
sqlStmt->setString(5, "Path");
sqlStmt->executeUpdate();

sqlResult = sqlStmt->getResultSet();

//Make sure everything was executed ok
if (sqlResult->rowsCount() > 0) {
    sqlResult->next();
    int image_id = sqlResult->getInt("ID");
}

注意:我在 sql 字符串中使用了 SELECT,因为 save_item_image 实际上是一个返回插入图像的 id 的函数。 我需要使用这种方法,因为没有其他方法可以获取在 C++ 连接器中最后插入的 ID(我可以找到)。在其他 MySql 库中,有一个 last_insert_id() 命令,但在连接器中没有。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-02
    • 2010-12-19
    • 1970-01-01
    • 2013-08-14
    • 2020-06-07
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    相关资源
    最近更新 更多