问题描述:

I am working on a VC++ cli application and I need to store an image into a MySql Database. I realize that this is usually not a good practice but due to the limited access to the file system this is the way I have to go.

So I have been able to get the image into a managed unsigned char array, which looks like what I have to do from the examples I have found online (which are mostly in C# and contain commands not available). I just need to figure out how to get this into the database, I am at a loss and my searches have not turned up anything useful with VC++ atleast.

Here is what I need to do, I have a managed array:

array<unsigned char>^ imageSource;

that contains the bytes of the image by using:

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);

Next I need to save it into my Database:

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();

As I understand it the setBlob function is requiring a std::istream to read the data. I am not sure how to go about this, this is the main hangup I have.

网友答案:

I finally figured this out and wanted to post an answer in case anyone else is looking for an answer to this.

The easiest way to accomplish this is by using pin_ptr to reference the first element in the managed array which is actually a pointer to the entire array. Next we cast to another pointer and finally to a char* pointer. Last in order to use this in setBlob we need to create a memory buffer for the istream.

Here is a working example:

Read the Image file to a managed array:

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);

Memory Buffer

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

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

Finally the MySQL Code:

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");
}

Note: I used a SELECT in the sql string because save_item_image is actually a function that returns the id of the inserted image. I needed to use this method because there is no other way to get the last inserted ID (that I could find) in the C++ Connector. In other MySql libraries there is a last_insert_id() command but not in the connector.

相关阅读:
Top