PostgreSQL 使用 C libpq 将文件保存和选择为大对象
PostgreSQL Save and Pick files as large objects with C libpq
我在这个问题上工作了 2 周,但没有任何结果。有人知道如何在不丢失格式和任何数据的情况下使用带有 blob 或 bytea 的 lipq 进行管理吗?导出的文件大小为 0B,我无法理解将文件从 C 上传到 postgreSQL 数据库并以正确的格式和功能再次选择它必须遵循的步骤。任何帮助都会很棒。我几乎尝试了网上的每一个例子和理论,甚至PG文档和手册,都没办法。我即将退出编程并成为农民(不是开玩笑 xD)。提前谢谢你。
代码修改后,我选择了一个比上传的文件高59字节的文件作为大对象。感觉我更接近了,但改变了我对使用大对象的想法。
#include "libpq/libpq-fs.h"
#include "libpq-fe.h"
int main(int argc, char* argv[])
{
//*************************** IMPORT TEST **********
manager.conn = manager.ConnectDB(); // my manager, working fine
Oid blob;
char* picName = new char[]{ "powerup.png" };
PGresult* res;
ress = PQexec(manager.conn, "begin");
PQclear(res);
blob = lo_import(manager.conn, "powerup.png");
cout << endl << "import returned oid " << blob;
//res = PQexec(manager.conn, "end");
//PQclear(res);
string sentenceB = "INSERT INTO testblob(filename, fileoid) VALUES('powerup.png', '" + std::to_string(blob) + "')";
manager.GenericQuery(manager.conn, sentenceB); //same as PQexec + result evaluation, works ok
PQclear(res);
//*************************** EXPORT TEST **********
OidManager oidm;
oidm.exportFile(manager.conn, blob, picName); // Ill show the function content at the end
res = PQexec(manager.conn, "end"); //SAME TRANSACTION TO AVOID LOSING THE OID, CHANGES AFTER TRANSACTION...
PQclear(res);
manager.CloseConn(manager.conn); // my manager, works fine
return true;
}
// oidm.exportFile() FUNCTION DETAIL
// code from: 35.5 Example Program Chapter 34 Large Objects
// https://www.postgresql.org/docs/10/lo-examplesect.html
void OidManager::exportFile(PGconn* conn, Oid lobjId, char* filename)
{
int lobj_fd;
char buf[BUFSIZE];
int nbytes,
tmp;
int fd;
/*
* open the large object
*/
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0)
fprintf(stderr, "cannot open large object %u", lobjId);
/*
* open the file to be written to
*/
fd = _open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (fd < 0)
{ /* error */
fprintf(stderr, "cannot open unix file\"%s\"",
filename);
}
/*
* read in from the inversion file and write to the Unix file
*/
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0)
{
tmp = _write(fd, buf, nbytes);
if (tmp < nbytes)
{
fprintf(stderr, "error while writing \"%s\"",
filename);
}
}
lo_close(conn, lobj_fd);
_close(fd);
return;
}
喜欢the documentation 说:
The descriptor is only valid for the duration of the current transaction.
因此您必须在同一个事务中调用 lo_open
和 lo_read
。
不要使用大对象。 They are slow, complicated to use and give you all kinds of serious trouble (for example, if you have many of them)。使用bytea
,那么你的代码会变得简单很多。
我在这个问题上工作了 2 周,但没有任何结果。有人知道如何在不丢失格式和任何数据的情况下使用带有 blob 或 bytea 的 lipq 进行管理吗?导出的文件大小为 0B,我无法理解将文件从 C 上传到 postgreSQL 数据库并以正确的格式和功能再次选择它必须遵循的步骤。任何帮助都会很棒。我几乎尝试了网上的每一个例子和理论,甚至PG文档和手册,都没办法。我即将退出编程并成为农民(不是开玩笑 xD)。提前谢谢你。
代码修改后,我选择了一个比上传的文件高59字节的文件作为大对象。感觉我更接近了,但改变了我对使用大对象的想法。
#include "libpq/libpq-fs.h"
#include "libpq-fe.h"
int main(int argc, char* argv[])
{
//*************************** IMPORT TEST **********
manager.conn = manager.ConnectDB(); // my manager, working fine
Oid blob;
char* picName = new char[]{ "powerup.png" };
PGresult* res;
ress = PQexec(manager.conn, "begin");
PQclear(res);
blob = lo_import(manager.conn, "powerup.png");
cout << endl << "import returned oid " << blob;
//res = PQexec(manager.conn, "end");
//PQclear(res);
string sentenceB = "INSERT INTO testblob(filename, fileoid) VALUES('powerup.png', '" + std::to_string(blob) + "')";
manager.GenericQuery(manager.conn, sentenceB); //same as PQexec + result evaluation, works ok
PQclear(res);
//*************************** EXPORT TEST **********
OidManager oidm;
oidm.exportFile(manager.conn, blob, picName); // Ill show the function content at the end
res = PQexec(manager.conn, "end"); //SAME TRANSACTION TO AVOID LOSING THE OID, CHANGES AFTER TRANSACTION...
PQclear(res);
manager.CloseConn(manager.conn); // my manager, works fine
return true;
}
// oidm.exportFile() FUNCTION DETAIL
// code from: 35.5 Example Program Chapter 34 Large Objects
// https://www.postgresql.org/docs/10/lo-examplesect.html
void OidManager::exportFile(PGconn* conn, Oid lobjId, char* filename)
{
int lobj_fd;
char buf[BUFSIZE];
int nbytes,
tmp;
int fd;
/*
* open the large object
*/
lobj_fd = lo_open(conn, lobjId, INV_READ);
if (lobj_fd < 0)
fprintf(stderr, "cannot open large object %u", lobjId);
/*
* open the file to be written to
*/
fd = _open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
if (fd < 0)
{ /* error */
fprintf(stderr, "cannot open unix file\"%s\"",
filename);
}
/*
* read in from the inversion file and write to the Unix file
*/
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0)
{
tmp = _write(fd, buf, nbytes);
if (tmp < nbytes)
{
fprintf(stderr, "error while writing \"%s\"",
filename);
}
}
lo_close(conn, lobj_fd);
_close(fd);
return;
}
喜欢the documentation 说:
The descriptor is only valid for the duration of the current transaction.
因此您必须在同一个事务中调用 lo_open
和 lo_read
。
不要使用大对象。 They are slow, complicated to use and give you all kinds of serious trouble (for example, if you have many of them)。使用bytea
,那么你的代码会变得简单很多。