Linux C/C++ 开发(学习笔记八):Mysql数据库图片存储

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
简介: Linux C/C++ 开发(学习笔记八):Mysql数据库图片存储

1.准备好一张图片文件,将图片read,存放到buffer

2.将图片数据(buffer)写入mysql

3.从mysql中读取图片数据(buffer)

4.将图片数据(buffer)写入磁盘

一、读入图片

//读取图片
//filename:path+file name
//buffer:store image data
int read_image(char* filename,char* buffer){
    if(filename==NULL||buffer==NULL) return -1;
    FILE *fp=fopen(filename,"rb");
    if(fp==NULL){
        printf("fopen faild\n");
        return -2;
    }
    //file size
    fseek(fp,0,SEEK_END);//把文件指针置到末尾
    int length=ftell(fp);//返回当前文件流的指针位置,也就是偏移量,文件大小file size 
    fseek(fp,0,SEEK_SET);//把文件指针置到开头
    int size=fread(buffer,1,length,fp);//每次读1个字节,读length次。读取的参数放到buffer里
    if(size!=length){
        printf("fread faild\n");
        return -3;
    }
    fclose(fp);
    return size;
}

二、图片数据写入磁盘

//图片写入到磁盘(参数1:保存的文件名 参数2:要写的数据   参数3:数据长度)
int write_image(char* filename,char* buffer,int length){
    if(filename==NULL||buffer==NULL||length<=0) return -1;
    FILE *fp=fopen(filename,"wb+");//w表示写入 b表示二进制 +表示,如果文件不存在则会创建,存在则会直接写入
    if(fp==NULL){
        printf("fopen faild\n");
        return -2;
    }
    int size=fwrite(buffer,1,length,fp);//从buffer写到fp中,每次写1个字节,写length次
    if(size!=length){
        printf("fwirte failded:%d\n",size);
        return -3;
    }
    fclose(fp);
    return size;
}

三、表中增加图片数据一列

在表中加一列U_IMG,存放图片数据

ALTER TABLE TBL_USER ADD U_IMG BLOB;

变成下面这样

四、将图片数据存入Mysql服务器

MySQL C语言接口-预处理语句

mysql stmt语法_mysql中SQL执行过程详解与用于预处理语句的SQL语法

//插入图片的SQL语句,由于不知道传入的图片是什么,用?作为占位符
#define SQL_INSERT_IMG_USER "insert TBL_USER(U_NAME,U_GENDER,U_IMG) value('Dog','man',?);"  
int mysql_write(MYSQL* handle,char* buffer,int length){
    if(handle==NULL||buffer==NULL||length<=0) return -1;
    MYSQL_STMT *stmt=mysql_stmt_init(handle);//在mysql中创建一个存储空间
    int ret=mysql_stmt_prepare(stmt,SQL_INSERT_IMG_USER,strlen(SQL_INSERT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare:%s\n",mysql_error(handle));
        return -2;
    }
    MYSQL_BIND param={0};
    param.buffer_type=MYSQL_TYPE_LONG_BLOB;
    param.buffer=NULL;
    param.is_null=0;
    param.length=NULL;
    ret=mysql_stmt_bind_param(stmt,&param);
    if(ret){
        printf("mysql_stmt_bind_param:%s\n",mysql_error(handle));
        return -3;
    }
    ret=mysql_stmt_send_long_data(stmt,0,buffer,length);//允许应用程序分块地将参数数据发送到服务器
    if(ret){
        printf("mysql_stmt_send_long_data:%s\n",mysql_error(handle));
        return -4;
    }
    ret=mysql_stmt_execute(stmt);//将当前绑定的参数标记符的值发送到服务器,服务器用新提供的数据替换标记符
    if(ret){
        printf("mysql_stmt_execute:%s\n",mysql_error(handle));
        return -5;
    }
    ret=mysql_stmt_close(stmt);
    if(ret){
        printf("mysql_stmt_close:%s\n",mysql_error(handle));
        return -6;
    }
    return ret;
}

五、将图像数据从Mysql服务器中取出

#define SQL_SELECT_IMG_USER "SELECT U_IMG FROM TBL_USER WHERE U_NAME='Dog';"
int mysql_read(MYSQL* handle,char* buffer,int length){
    if(handle==NULL||buffer==NULL||length<=0) return -1;
    MYSQL_STMT *stmt=mysql_stmt_init(handle);//在mysql中创建一个存储空间
    int ret=mysql_stmt_prepare(stmt,SQL_SELECT_IMG_USER,strlen(SQL_SELECT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare:%s\n",mysql_error(handle));
        return -2;
    }
    MYSQL_BIND result={0};
    result.buffer_type=MYSQL_TYPE_LONG_BLOB;
    unsigned long total_length=0;
    result.length=&total_length;
    ret=mysql_stmt_bind_result(stmt,&result);
    if(ret){
        printf("mysql_stmt_bind_result:%s\n",mysql_error(handle));
        return -3;
    }
    ret=mysql_stmt_execute(stmt);//执行后,长度数据会存储到total_length中
    if(ret){
        printf("mysql_stmt_execute:%s\n",mysql_error(handle));
        return -4;
    }
    //数据从管道里拿出来
    ret=mysql_stmt_store_result(stmt);
    if(ret){
        printf("mysql_stmt_store_result:%s\n",mysql_error(handle));
        return -5;
    }
    while(1){
        ret=mysql_stmt_fetch(stmt);
        if(ret!=0&&ret!=MYSQL_DATA_TRUNCATED) break;
        int start=0;
        while(start<(int)total_length){
            result.buffer=buffer+start;
            result.buffer_length=1;//每次读取得长度为1
            mysql_stmt_fetch_column(stmt,&result,0,start);
            start+=result.buffer_length;
        }
    }
    mysql_stmt_close(stmt);
    return total_length;
}

六、完整代码

#include<mysql.h>
#include<stdio.h>
#include<string.h>
#define KING_DB_SERVER_IP "192.168.192.128" //ip
#define KING_DB_SERVER_PORT 3306            //端口号
#define KING_DB_USERNAME "admin"            //用户名
#define KING_DB_PASSWORD "123456"           //密码
#define KING_DB_DEFAULTDB "KING_DB"         //数据库名
//插入图片的SQL语句,由于不知道传入的图片是什么,用?作为占位符
#define SQL_INSERT_IMG_USER "insert TBL_USER(U_NAME,U_GENDER,U_IMG) value('Dog','man',?);"  
#define SQL_SELECT_IMG_USER "SELECT U_IMG FROM TBL_USER WHERE U_NAME='Dog';"
#define FILE_IMAGE_LENGTH (64*1024)
//读取图片
//filename:path+file name
//buffer:store image data
int read_image(char* filename,char* buffer){
    if(filename==NULL||buffer==NULL) return -1;
    FILE *fp=fopen(filename,"rb");
    if(fp==NULL){
        printf("fopen faild\n");
        return -2;
    }
    //file size
    fseek(fp,0,SEEK_END);//把文件指针置到末尾
    int length=ftell(fp);//返回当前文件流的指针位置,也就是偏移量,文件大小file size 
    fseek(fp,0,SEEK_SET);//把文件指针置到开头
    int size=fread(buffer,1,length,fp);//每次读1个字节,读length次。读取的参数放到buffer里
    if(size!=length){
        printf("fread faild\n");
        return -3;
    }
    fclose(fp);
    return size;
}
//图片写入到磁盘(参数1:保存的文件名 参数2:要写的数据   参数3:数据长度)
int write_image(char* filename,char* buffer,int length){
    if(filename==NULL||buffer==NULL||length<=0) return -1;
    FILE *fp=fopen(filename,"wb+");//w表示写入 b表示二进制 +表示,如果文件不存在则会创建,存在则会直接写入
    if(fp==NULL){
        printf("fopen faild\n");
        return -2;
    }
    int size=fwrite(buffer,1,length,fp);//从buffer写到fp中,每次写1个字节,写length次
    if(size!=length){
        printf("fwirte failded:%d\n",size);
        return -3;
    }
    fclose(fp);
    return size;
}
int mysql_write(MYSQL* handle,char* buffer,int length){
    if(handle==NULL||buffer==NULL||length<=0) return -1;
    MYSQL_STMT *stmt=mysql_stmt_init(handle);//在mysql中创建一个存储空间
    int ret=mysql_stmt_prepare(stmt,SQL_INSERT_IMG_USER,strlen(SQL_INSERT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare:%s\n",mysql_error(handle));
        return -2;
    }
    MYSQL_BIND param={0};
    param.buffer_type=MYSQL_TYPE_LONG_BLOB;
    param.buffer=NULL;
    param.is_null=0;
    param.length=NULL;
    ret=mysql_stmt_bind_param(stmt,&param);
    if(ret){
        printf("mysql_stmt_bind_param:%s\n",mysql_error(handle));
        return -3;
    }
    ret=mysql_stmt_send_long_data(stmt,0,buffer,length);//允许应用程序分块地将参数数据发送到服务器
    if(ret){
        printf("mysql_stmt_send_long_data:%s\n",mysql_error(handle));
        return -4;
    }
    ret=mysql_stmt_execute(stmt);//将当前绑定的参数标记符的值发送到服务器,服务器用新提供的数据替换标记符
    if(ret){
        printf("mysql_stmt_execute:%s\n",mysql_error(handle));
        return -5;
    }
    ret=mysql_stmt_close(stmt);
    if(ret){
        printf("mysql_stmt_close:%s\n",mysql_error(handle));
        return -6;
    }
    return ret;
}
int mysql_read(MYSQL* handle,char* buffer,int length){
    if(handle==NULL||buffer==NULL||length<=0) return -1;
    MYSQL_STMT *stmt=mysql_stmt_init(handle);//在mysql中创建一个存储空间
    int ret=mysql_stmt_prepare(stmt,SQL_SELECT_IMG_USER,strlen(SQL_SELECT_IMG_USER));
    if(ret){
        printf("mysql_stmt_prepare:%s\n",mysql_error(handle));
        return -2;
    }
    MYSQL_BIND result={0};
    result.buffer_type=MYSQL_TYPE_LONG_BLOB;
    unsigned long total_length=0;
    result.length=&total_length;
    ret=mysql_stmt_bind_result(stmt,&result);
    if(ret){
        printf("mysql_stmt_bind_result:%s\n",mysql_error(handle));
        return -3;
    }
    ret=mysql_stmt_execute(stmt);//执行后,长度数据会存储到total_length中
    if(ret){
        printf("mysql_stmt_execute:%s\n",mysql_error(handle));
        return -4;
    }
    //数据从管道里拿出来
    ret=mysql_stmt_store_result(stmt);
    if(ret){
        printf("mysql_stmt_store_result:%s\n",mysql_error(handle));
        return -5;
    }
    while(1){
        ret=mysql_stmt_fetch(stmt);
        if(ret!=0&&ret!=MYSQL_DATA_TRUNCATED) break;
        int start=0;
        while(start<(int)total_length){
            result.buffer=buffer+start;
            result.buffer_length=1;//每次读取得长度为1
            mysql_stmt_fetch_column(stmt,&result,0,start);
            start+=result.buffer_length;
        }
    }
    mysql_stmt_close(stmt);
    return total_length;
}
int main(){
    MYSQL mysql;
    if(!mysql_init(&mysql)){//mysql初始化并判断是否出错(返回0为失败)
        printf("mysql_init:%s\n",mysql_error(&mysql));//mysql_error() 函数返回上一个 MySQL 操作产生的文本错误信息
        return -1;
    }
    if(!mysql_real_connect(&mysql,KING_DB_SERVER_IP,KING_DB_USERNAME,KING_DB_PASSWORD, 
    KING_DB_DEFAULTDB,KING_DB_SERVER_PORT,NULL,0)){ //连接mysql数据库,并判断是否出错(返回0为失败)
        printf("mysql_real_connect:%s\n",mysql_error(&mysql));
        return -2;
    }
    printf("case:mysql --> read image and write mysql\n");
    char buffer[FILE_IMAGE_LENGTH]={0};
    int length = read_image("0voice.jpg",buffer);
    if(length<0) goto Exit;
    mysql_write(&mysql,buffer,length);
    printf("case:mysql-->read mysql and write image\n");
    memset(buffer,0,FILE_IMAGE_LENGTH);
    length=mysql_read(&mysql,buffer,FILE_IMAGE_LENGTH);
    write_image("a.jpg",buffer,length);
Exit:
    mysql_close(&mysql);
    return 0;
}


相关实践学习
自建数据库迁移到云数据库
本场景将引导您将网站的自建数据库平滑迁移至云数据库RDS。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
12月前
|
Ubuntu 关系型数据库 Linux
Linux数据库安装
本文介绍了在CentOS 8.0和Ubuntu 22.04系统上安装、配置和启动MariaDB数据库服务器的详细步骤。包括通过`yum`和`apt`包管理器安装MariaDB服务,启动并检查服务运行状态,设置root用户密码以及连接数据库的基本操作。此外,还展示了如何在Ubuntu上更新软件包列表、安装依赖项,并验证MariaDB的版本和运行状态。通过这些步骤,用户可以成功部署并初始化MariaDB环境,为后续数据库管理与应用开发奠定基础。
682 61
|
自然语言处理 数据库 iOS开发
DBeaver Ultimate Edtion 25.0 Multilingual (macOS, Linux, Windows) - 通用数据库工具
DBeaver Ultimate Edtion 25.0 Multilingual (macOS, Linux, Windows) - 通用数据库工具
873 12
DBeaver Ultimate Edtion 25.0 Multilingual (macOS, Linux, Windows) - 通用数据库工具
|
存储 算法 C++
【C++数据结构——图】图的邻接矩阵和邻接表的存储(头歌实践教学平台习题)【合集】
本任务要求编写程序实现图的邻接矩阵和邻接表的存储。需掌握带权有向图、图的邻接矩阵及邻接表的概念。邻接矩阵用于表示顶点间的连接关系,邻接表则通过链表结构存储图信息。测试输入为图的顶点数、边数及邻接矩阵,预期输出为Prim算法求解结果。通关代码提供了完整的C++实现,包括输入、构建和打印邻接矩阵与邻接表的功能。
657 10
|
IDE 开发工具 C语言
C++一分钟之-嵌入式编程与裸机开发
通过这些内容的详细介绍和实例解析,希望能帮助您深入理解C++在嵌入式编程与裸机开发中的应用,提高开发效率和代码质量。
459 13
|
关系型数据库 MySQL Linux
Linux下mysql数据库的导入与导出以及查看端口
本文详细介绍了在Linux下如何导入和导出MySQL数据库,以及查看MySQL运行端口的方法。通过这些操作,用户可以轻松进行数据库的备份与恢复,以及确认MySQL服务的运行状态和端口。掌握这些技能,对于日常数据库管理和维护非常重要。
651 8
|
数据库连接 Linux Shell
Linux下ODBC与 南大通用GBase 8s数据库的无缝连接配置指南
本文详细介绍在Linux系统下配置GBase 8s数据库ODBC的过程,涵盖环境变量设置、ODBC配置文件编辑及连接测试等步骤。首先配置数据库环境变量如GBASEDBTDIR、PATH等,接着修改odbcinst.ini和odbc.ini文件,指定驱动路径、数据库名称等信息,最后通过catalog.c工具或isql命令验证ODBC连接是否成功。
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
884 3
|
监控 关系型数据库 MySQL
Linux环境下MySQL数据库自动定时备份策略
在Linux环境下,MySQL数据库的自动定时备份是确保数据安全和可靠性的重要措施。通过设置定时任务,我们可以每天自动执行数据库备份,从而减少人为错误和提高数据恢复的效率。本文将详细介绍如何在Linux下实现MySQL数据库的自动定时备份。
444 3
WK
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
530 0
WK
|
安全 Java 编译器
C++和Java哪个更适合开发web网站
在Web开发领域,C++和Java各具优势。C++以其高性能、低级控制和跨平台性著称,适用于需要高吞吐量和低延迟的场景,如实时交易系统和在线游戏服务器。Java则凭借其跨平台性、丰富的生态系统和强大的安全性,广泛应用于企业级Web开发,如企业管理系统和电子商务平台。选择时需根据项目需求和技术储备综合考虑。
WK
566 0