MySQL C API 编程
最后修改于 2020 年 9 月 23 日
这是一个针对 MySQL 数据库的 C 语言编程教程。它涵盖了使用 C API 进行 MySQL 编程的基础知识。您也可以考虑查看 ZetCode 上的 MySQL 教程。
关于 MySQL 数据库
MySQL 是一款领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在 Web 领域尤其流行。MySQL 目前归 Oracle 公司所有。MySQL 数据库可在大多数主流操作系统平台上使用。它可以在 BSD Unix、Linux、Windows 或 Mac OS 上运行。
MariaDB 是一个由社区开发、有商业支持的 MySQL 关系型数据库管理系统的分支。
$ sudo apt install default-libmysqlclient-dev
为了能够编译 C 语言示例,我们需要安装 MySQL C 开发库。上面的命令行展示了如何在基于 Debian 的 Linux 系统上进行安装。
C99
本教程使用 C99 标准。对于 GNU C 编译器,我们需要添加 -std=c99 选项。对于 Windows 用户,强烈推荐使用 Pelles C IDE。(MSVC 不支持 C99。)
MYSQL *con = mysql_init(NULL);
在 C99 中,我们可以将声明与代码混合在一起。在旧的 C 程序中,我们需要将这行代码分成两行。
MySQL C 第一个示例
在第一个示例中,我们测试一个 MySQL 函数的调用。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
printf("MySQL client version: %s\n", mysql_get_client_info());
exit(0);
}
mysql_get_client_info 函数显示 MySQL 客户端的版本。
#include <stdio.h> #include <mysql.h> #include <stdlib.h>
我们包含了必要的头文件。
printf("MySQL client version: %s\n", mysql_get_client_info());
这行代码输出了 MySQL 客户端的版本。为此,我们使用了 mysql_get_client_info 函数调用。
exit(0);
我们从脚本中退出。
$ c99 version.c -o version `mysql_config --cflags --libs`
这是我们编译代码示例的方式。
$ ./version MySQL client version: 10.3.24
这是输出。
MySQL C 创建数据库
下一个代码示例将创建一个数据库。该代码示例可以分为以下几个部分:
- 初始化连接句柄结构
- 创建连接
- 执行查询
- 关闭连接
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "root", "root_passwd",
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
if (mysql_query(con, "CREATE DATABASE testdb"))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_close(con);
exit(0);
}
该代码示例连接到 MySQL 数据库系统并创建一个名为 testdb 的新数据库。
MYSQL *con = mysql_init(NULL);
mysql_init 函数分配或初始化一个适用于 mysql_real_connect 函数的 MYSQL 对象。请记住,这里是 C99 标准。
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
我们检查返回值。如果 mysql_init 函数失败,我们打印错误消息并终止应用程序。
if (mysql_real_connect(con, "localhost", "root", "root_passwd",
NULL, 0, NULL, 0) == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_real_connect 函数建立与数据库的连接。我们向该函数提供连接句柄、主机名、用户名和密码参数。其他四个参数分别是数据库名、端口号、Unix 套接字和客户端标志。创建新数据库需要超级用户权限。
if (mysql_query(con, "CREATE DATABASE testdb"))
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
mysql_query 执行 SQL 语句。在我们的例子中,该语句创建了一个新的数据库。
mysql_close(con);
最后,我们关闭数据库连接。
mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | testdb | +--------------------+ 3 rows in set (0.00 sec)
这证明了数据库已成功创建。
MySQL C 创建并填充表
在创建新表之前,我们先创建一个将在本教程其余部分使用的用户。
mysql> CREATE USER user12@localhost IDENTIFIED BY '34klq*';
我们创建了一个新用户 user12。
mysql> GRANT ALL ON testdb.* to user12@localhost;
这里我们将 testdb 数据库的所有权限授予 user12。
下一个代码示例创建一个表并向其中插入一些数据。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "%s\n", mysql_error(con));
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "DROP TABLE IF EXISTS cars")) {
finish_with_error(con);
}
if (mysql_query(con, "CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), price INT)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(1,'Audi',52642)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(2,'Mercedes',57127)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(3,'Skoda',9000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(4,'Volvo',29000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(5,'Bentley',350000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(6,'Citroen',21000)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(7,'Hummer',41400)")) {
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO cars VALUES(8,'Volkswagen',21600)")) {
finish_with_error(con);
}
mysql_close(con);
exit(0);
}
这里我们没有使用任何新的 MySQL 函数调用。我们使用 mysql_query 函数调用来创建表和插入数据。
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
为了避免不必要的重复,我们创建了一个自定义的 finish_with_error 函数。
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
我们连接到 testdb 数据库。用户名是 user12,密码是 34klq*。第五个参数是数据库名。
if (mysql_query(con, "CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), price INT)")) {
finish_with_error(con);
}
这里我们创建一个名为 cars 的表。它有三列。
if (mysql_query(con, "INSERT INTO cars VALUES(1,'Audi',52642)")) {
finish_with_error(con);
}
我们向 cars 表中插入一行数据。
mysql> USE testdb; mysql> SHOW TABLES; +------------------+ | Tables_in_testdb | +------------------+ | cars | +------------------+ 1 row in set (0.00 sec)
我们显示数据库中的表。
mysql> SELECT * FROM cars; +------+------------+--------+ | Id | Name | Price | +------+------------+--------+ | 1 | Audi | 52642 | | 2 | Mercedes | 57127 | | 3 | Skoda | 9000 | | 4 | Volvo | 29000 | | 5 | Bentley | 350000 | | 6 | Citroen | 21000 | | 7 | Hummer | 41400 | | 8 | Volkswagen | 21600 | +------+------------+--------+ 8 rows in set (0.00 sec)
我们从表中查询所有数据。
MySQL C 检索数据
在下一个示例中,我们从表中检索数据。
我们需要执行以下步骤:
- 创建连接
- 执行查询
- 获取结果集
- 抓取所有可用行
- 释放结果集
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT * FROM cars"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(result);
mysql_close(con);
exit(0);
}
该示例显示了 cars 表中的所有行。
if (mysql_query(con, "SELECT * FROM cars"))
{
finish_with_error(con);
}
我们执行查询以检索 cars 表中的所有数据。
MYSQL_RES *result = mysql_store_result(con);
我们使用 mysql_store_result 函数获取结果集。MYSQL_RES 是一个用于保存结果集的结构体。
int num_fields = mysql_num_fields(result);
我们获取表中的字段(列)数。
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
我们抓取行并将其打印到屏幕上。
mysql_free_result(result); mysql_close(con);
我们释放资源。
$ ./retrieva_data 1 Audi 52642 2 Mercedes 57127 3 Skoda 9000 4 Volvo 29000 5 Bentley 350000 6 Citroen 21000 7 Hummer 41400 8 Volkswagen 21600
这是输出。
MySQL C 获取最后插入行的 ID
有时,我们需要确定最后插入行的 ID。我们可以通过调用 mysql_insert_id 函数来确定最后插入行的 ID。该函数仅在表中定义了 AUTO_INCREMENT 列时才有效。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "DROP TABLE IF EXISTS writers"))
{
finish_with_error(con);
}
char *sql = "CREATE TABLE writers(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255))";
if (mysql_query(con, sql))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Leo Tolstoy')"))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Jack London')"))
{
finish_with_error(con);
}
if (mysql_query(con, "INSERT INTO writers(name) VALUES('Honore de Balzac')"))
{
finish_with_error(con);
}
int id = mysql_insert_id(con);
printf("The last inserted row id is: %d\n", id);
mysql_close(con);
exit(0);
}
创建了一个新表。三行数据被插入到表中。我们确定了最后插入行的 ID。
char *sql = "CREATE TABLE writers(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255))";
id 列的类型是 AUTO_INCREMENT。
int id = mysql_insert_id(con);
mysql_insert_id 函数返回由前一个 INSERT 或 UPDATE 语句为 AUTO_INCREMENT 列生成的值。
$ ./last_row_id The last inserted row id is: 3
这是输出。
MySQL C 获取列标题
在下一个示例中,我们从表中检索数据及其列名。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT * FROM cars LIMIT 3"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
MYSQL_FIELD *field;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
if (i == 0)
{
while(field = mysql_fetch_field(result))
{
printf("%s ", field->name);
}
printf("\n");
}
printf("%s ", row[i] ? row[i] : "NULL");
}
}
printf("\n");
mysql_free_result(result);
mysql_close(con);
exit(0);
}
我们打印 cars 表的前三行数据。我们还包括了列标题。
MYSQL_FIELD *field;
MYSQL_FIELD 结构体包含有关字段的信息,例如字段的名称、类型和大小。字段的值不属于此结构体的一部分;它们包含在 MYSQL_ROW 结构体中。
if (i == 0)
{
while(field = mysql_fetch_field(result))
{
printf("%s ", field->name);
}
printf("\n");
}
第一行包含了列标题。mysql_fetch_field 调用返回一个 MYSQL_FIELD 结构体。我们从这个结构体中获取列标题名称。
$ ./headers id name price 1 Audi 52642 2 Mercedes 57127 3 Skoda 9000
这是我们程序的输出。
MySQL C 多条语句
可以在一次查询中执行多条 SQL 语句。我们必须在连接方法中设置 CLIENT_MULTI_STATEMENTS 标志。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
int status = 0;
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, CLIENT_MULTI_STATEMENTS) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT name FROM cars WHERE id=2;\
SELECT name FROM cars WHERE id=3;SELECT name FROM cars WHERE id=6"))
{
finish_with_error(con);
}
do {
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
MYSQL_ROW row = mysql_fetch_row(result);
printf("%s\n", row[0]);
mysql_free_result(result);
status = mysql_next_result(con);
if (status > 0) {
finish_with_error(con);
}
} while(status == 0);
mysql_close(con);
exit(0);
}
在这个示例中,我们在一次查询中执行了三条 SELECT 语句。
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, CLIENT_MULTI_STATEMENTS) == NULL)
{
finish_with_error(con);
}
mysql_real_connect 方法的最后一个选项是客户端标志。它用于启用某些功能。CLIENT_MULTI_STATEMENTS 启用多条语句的执行。默认情况下这是禁用的。
if (mysql_query(con, "SELECT name FROM cars WHERE id=2;\
SELECT name FROM cars WHERE id=3;SELECT name FROM cars WHERE id=6"))
{
finish_with_error(con);
}
查询由三条 SELECT 语句组成。它们由分号 ; 字符分隔。反斜杠字符 \ 用于将字符串分成两行。它与多条语句无关。
do {
...
} while(status == 0);
代码被放置在 do/while 语句之间。数据检索需要分多个周期完成。我们分别为每个 SELECT 语句检索数据。
status = mysql_next_result(con);
我们期望有多个结果集。因此,我们调用 mysql_next_result 函数。它读取下一个语句的结果并返回一个状态以指示是否存在更多结果。如果执行成功并且还有更多结果,该函数返回 0。如果执行成功但没有更多结果,则返回 -1。最后,如果发生错误,它返回一个大于零的值。
if (status > 0) {
finish_with_error(con);
}
我们检查错误。
$ ./multiple_statements Mercedes Skoda Citroen
示例输出。
MySQL C 插入图片
有些人喜欢将图片放入数据库,有些人则喜欢将它们保存在文件系统中以供其应用程序使用。当我们处理大量图片时,会出现技术难题。图片是二进制数据。MySQL 数据库有一个特殊的数据类型来存储二进制数据,称为 BLOB(Binary Large Object,二进制大对象)。
mysql> CREATE TABLE images(id INT PRIMARY KEY, data MEDIUMBLOB);
在我们的示例中,我们创建了一个新的 Images 表。图片大小最大可达 16 MB。这是由 MEDIUMBLOB 数据类型决定的。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
FILE *fp = fopen("sid.jpg", "rb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
fseek(fp, 0, SEEK_END);
if (ferror(fp)) {
fprintf(stderr, "fseek() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
int flen = ftell(fp);
if (flen == -1) {
perror("error occurred");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
fseek(fp, 0, SEEK_SET);
if (ferror(fp)) {
fprintf(stderr, "fseek() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
char data[flen+1];
int size = fread(data, 1, flen, fp);
if (ferror(fp)) {
fprintf(stderr, "fread() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
char chunk[2*size+1];
mysql_real_escape_string(con, chunk, data, size);
char *st = "INSERT INTO images(id, data) VALUES(1, '%s')";
size_t st_len = strlen(st);
char query[st_len + 2*size+1];
int len = snprintf(query, st_len + 2*size+1, st, chunk);
if (mysql_real_query(con, query, len))
{
finish_with_error(con);
}
mysql_close(con);
exit(0);
}
在这个示例中,我们向 images 表中插入一张图片。
#include <string.h>
这个 include 是为了使用 strlen 函数。
FILE *fp = fopen("woman.jpg", "rb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
这里我们打开图片文件。在当前工作目录中,我们应该有一个 sid.jpg 文件。
fseek(fp, 0, SEEK_END);
if (ferror(fp)) {
fprintf(stderr, "fseek() failed\n");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
我们使用 fseek 函数将文件指针移动到文件末尾。我们将要确定图片的大小。如果发生错误,错误指示器会被设置。我们使用 ferror 函数检查该指示器。如果发生错误,我们也会关闭已打开的文件句柄。
int flen = ftell(fp);
if (flen == -1) {
perror("error occurred");
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
exit(1);
}
对于二进制流,ftell 函数返回从文件开头算起的字节数,即图片文件的大小。如果发生错误,该函数返回 -1 并设置 errno。perror 函数将 errno 的值解释为错误消息,并将其打印到标准错误输出流。
char data[flen+1];
在这个数组中,我们将存储图片数据。
int size = fread(data, 1, flen, fp);
我们从文件指针读取数据并将其存储在 data 数组中。函数返回成功读取的元素总数。
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
数据读取后,我们可以关闭文件句柄。
char chunk[2*size+1]; mysql_real_escape_string(con, chunk, data, size);
mysql_real_escape_string 函数会在传入字符串中某些有潜在危险的字符前添加转义字符,即反斜杠 \。这有助于防止 SQL 注入攻击。新的缓冲区长度必须至少为 2*size+1。
char *st = "INSERT INTO images(id, data) VALUES(1, '%s')"; size_t st_len = strlen(st);
这里我们开始构建 SQL 语句。我们使用 strlen 函数确定 SQL 字符串的大小。
char query[st_len + 2*size+1]; int len = snprintf(query, st_len + 2*size+1, st, chunk);
查询字符串必须足够长,以包含 SQL 语句字符串的大小和图片文件的大小。我们使用 snprintf 函数将格式化的输出写入查询缓冲区。
if (mysql_real_query(con, query, len))
{
finish_with_error(con);
};
我们使用 mysql_real_query 函数执行查询。mysql_query 不能用于包含二进制数据的语句;我们必须改用 mysql_real_query。
MySQL C 查询图片
在前面的示例中,我们向数据库中插入了一张图片。在接下来的示例中,我们从数据库中查询已插入的图片。
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
int main(int argc, char **argv)
{
FILE *fp = fopen("sid2.jpg", "wb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
MYSQL *con = mysql_init(NULL);
if (con == NULL)
{
fprintf(stderr, "mysql_init() failed\n");
exit(1);
}
if (mysql_real_connect(con, "localhost", "user12", "34klq*",
"testdb", 0, NULL, 0) == NULL)
{
finish_with_error(con);
}
if (mysql_query(con, "SELECT data FROM images WHERE id=1"))
{
finish_with_error(con);
}
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL)
{
finish_with_error(con);
}
MYSQL_ROW row = mysql_fetch_row(result);
unsigned long *lengths = mysql_fetch_lengths(result);
if (lengths == NULL) {
finish_with_error(con);
}
fwrite(row[0], lengths[0], 1, fp);
if (ferror(fp))
{
fprintf(stderr, "fwrite() failed\n");
mysql_free_result(result);
mysql_close(con);
exit(1);
}
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
mysql_free_result(result);
mysql_close(con);
exit(0);
}
在这个示例中,我们从数据库数据创建一个图片文件。
FILE *fp = fopen("sid2.jpg", "wb");
if (fp == NULL)
{
fprintf(stderr, "cannot open image file\n");
exit(1);
}
我们打开一个新的文件句柄用于写入。
if (mysql_query(con, "SELECT data FROM images WHERE id=1"))
{
finish_with_error(con);
}
我们从 images 表中选择 id 为 1 的行的 data 列。
MYSQL_ROW row = mysql_fetch_row(result);
行中包含原始数据。
unsigned long *lengths = mysql_fetch_lengths(result);
我们获取图片的长度。
fwrite(row[0], lengths[0], 1, fp);
if (ferror(fp))
{
fprintf(stderr, "fwrite() failed\n");
mysql_free_result(result);
mysql_close(con);
exit(1);
}
我们使用 fwrite 函数调用将检索到的数据写入磁盘。我们使用 ferror 函数检查错误指示器。
int r = fclose(fp);
if (r == EOF) {
fprintf(stderr, "cannot close file handler\n");
}
写入图片数据后,我们使用 fclose 函数关闭文件句柄。
这是 MySQL C API 教程。您可能还对 ZetCode 上的 PyMySQL 教程、MySQL Visual Basic 教程、PHP mysqli 教程、PostgreSQL C 教程或SQLite C 教程感兴趣。