Đây là kết quả của mã hoạt động tốt. Tôi có chút thời gian để đăng nó ngay bây giờ trong trường hợp nó có thể giúp ích cho ai đó. Tôi hơi khó hiểu cách hoạt động của bytea nhưng cuối cùng nó đã được giải quyết. Trân trọng kính chào quý vị.
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include "libpq/libpq-fs.h"
#include "libpq-fe.h"
#pragma comment(lib, "libpq.lib") /*!< Only for windows compilation */
int main(int argc, char* argv[])
{
ManageDB manager;
manager.conn = manager.ConnectDB(); // My manager, connects ok
const char* fileName = {"test.png"};
const char* fileNameOut = { "testOut.png" };
FILE* file = fopen(fileName, "rb");
if (file == NULL) cout << endl << "FILE WAS UNABLE TO BE READED" << endl;
fseek(file, 0, SEEK_END);
long int fileSize = ftell(file);
rewind(file);
unsigned char* buffRead = (unsigned char*)malloc(fileSize);
size_t bytes_read = fread(buffRead, 1, fileSize, file);
if (bytes_read != fileSize) cout << endl << "fread reading Error";
fclose(file);
size_t* sizeP = new size_t(fileSize);
const char* paramValues[3];
paramValues[0] = "1";
paramValues[1] = fileName;
paramValues[2] = reinterpret_cast<const char*>(buffRead); // type cast required to PQexeParams
const int paramFormats[3]{ 0,0,1 }; //0 = text, 1 = binary
const int paramLenghts[3]{ strlen(paramValues[0]), strlen(paramValues[1]), fileSize};
PGresult *res = PQexecParams(manager.conn, "INSERT INTO filebyte (id, filename, file) VALUES($1::text, $2::text, $3::bytea)",
3, /* params num */
NULL, /* let the backend deduce param type */
paramValues,
paramLenghts,
paramFormats,
1);
if (res && PQresultStatus(res) == PGRES_COMMAND_OK) cout << endl << "Inserted data to filebyte OK";
PQfreemem(res);
//************************download from DB*************************
const char* bytesFromDB = new const char[fileSize];
int sizeR;
// Table columns = id(text) | filename(text) | file(bytea)
const char* sentenceEx = "SELECT file FROM filebyte WHERE id='1'";
res = PQexec(manager.conn, sentenceEx);
if (res && PQresultStatus(res) == PGRES_TUPLES_OK)
{
sizeR = PQgetlength(res, 0, 0);
bytesFromDB = PQgetvalue(res, 0, 0);
}
else cout << endl << "Error at inserting file data in filebyte table";
string hex(bytesFromDB, 2, sizeR-2); //removing the first '\x' characters of the result.
// vars for converting to real bytes process
std::basic_string<uint8_t> bytes;
bytes.clear();
std::string nextbyte;
nextbyte.clear();
uint16_t byte;
// Iterate over every pair of hex values in the input string (e.g. "18", "0f", ...)
for (size_t i = 0; i < hex.length(); i += 2)
{
// Get current pair and store in nextbyte
nextbyte = hex.substr(i, 2);
// Put the pair into an istringstream and stream it through std::hex for
// conversion into an integer value.
// This will calculate the byte value of your string-represented hex value.
std::istringstream(nextbyte) >> std::hex >> byte;
// As the stream above does not work with uint8 directly, we have to cast it now.
// As every pair can have a maximum value of "ff",
// which is "11111111" (8 bits), we will not lose any information during this cast.
bytes.push_back(static_cast<uint8_t>(byte));
}
// string obj from bytes-"array"
std::string result(begin(bytes), end(bytes));
ofstream myFile(fileNameOut, ios::out | ios::ios_base::binary);
if (myFile.is_open())
{
myFile << result;
myFile.close();
}
else cout << endl << "Impossible to writte the file " << fileNameOut;
manager.CloseConn(manager.conn); //closes connection with database internally ok
PQfreemem(res);
free(buffRead);
delete sizeP;
free((char*)fileName[8]);
free((char*)fileNameOut[11]);
return true;
}