沐浴晨風想一想,今天該怎樣努力;踏著夕陽問一問,今天學到了什麼。
阿新 • • 發佈:2019-02-17
直接把檔案放入資料庫中比較適合小檔案,方便管理,比如頭像圖片和聲音,如果是較大型的檔案建議不要直接存進資料庫,而是放在伺服器,把檔案索引放在資料庫。
MYSQL 中有個資料物件是 BLOB,即 Binary Large Object,顧名思義也就是二進位制大型資料物件,用來記錄二進位制的資料,它有 4 種類型,分別是:tinyblob(255B)、blob(65KB)、mediumblob(16MB)、longblob(4GB)。
我在資料庫中建立了一張 images 表,如下圖:
先把用到的標頭檔案和預處理寫一下:
#include <winsock.h> #include <mysql.h> #include <stdio.h> #include <string.h> #include <malloc.h> #pragma comment(lib, "libmysql.lib") #define BYTE unsigned char #define FILE_MAX_SIZE (65 * 1024) /*檔案最大65KB*/
接下來的任務就是怎麼把資料記錄到 img 欄位,我用C語言寫了個函式,函式接受檔案路徑:
void insert(char *path) { FILE *fp; BYTE *img, data; long cnt = 0; MYSQL mysql; char *sql; /*讀取檔案*/ fp = fopen(path, "rb"); if (!fp) { printf("讀取檔案失敗\n"); return; } img = malloc(FILE_MAX_SIZE); //分配65KB的記憶體 memset(img, FILE_MAX_SIZE, 0); while (!feof(fp)) { fread(&data, 1, 1, fp); if (data == '\0') //將結束字元轉義 { img[cnt++] = '\\'; img[cnt++] = '0'; continue; } if (data == '\'' || data == '\\' /*|| data == '\"'*/) //這些字元也要轉義 { img[cnt++] = '\\'; } img[cnt++] = data; if (cnt == FILE_MAX_SIZE) { printf("檔案超過65KB\n"); free(img); fclose(fp); return; } } img[cnt] = '\0'; fclose(fp); /*操作資料庫*/ if (NULL == mysql_init(&mysql)) { printf("初始化資料庫失敗\n"); return; } if (NULL == mysql_real_connect(&mysql, "localhost", "root", "password", "test", 0, NULL, 0)) { printf("連線資料庫失敗\n"); return; } sql = malloc(126 + FILE_MAX_SIZE); memset(sql, 126 + FILE_MAX_SIZE, 0); sprintf(sql, "INSERT INTO images (img) VALUES ('%s')", img); if (0 != mysql_real_query(&mysql, sql, strlen(sql))) { printf("執行SQL語句出錯\n"); mysql_close(&mysql); free(sql); free(img); return; } mysql_close(&mysql); free(sql); free(img); printf("插入成功\n"); }
從以上程式碼可以看出整個過程是將檔案以二進位制形式讀出,然後再執行 SQL 語句。
下面我要將檔案從資料庫中讀取出來,存放本地,該函式結束檔案路徑和在資料庫中的 id 欄位:
void peek(char *filename, int id) { MYSQL mysql; FILE *fp; char sql[126]; MYSQL_RES *res; MYSQL_ROW row; long *length; /*操作資料庫*/ if (NULL == mysql_init(&mysql)) { printf("初始化資料庫失敗\n"); return; } if (NULL == mysql_real_connect(&mysql, "localhost", "root", "password", "test", 0, NULL, 0)) { printf("連線資料庫失敗\n"); return; } sprintf(sql, "SELECT img FROM images WHERE id=%d", id); if (0 != mysql_real_query(&mysql, sql, strlen(sql))) { printf("執行SQL語句出錯\n"); } res = mysql_store_result(&mysql); if (NULL == res) { printf("資料庫中無結果\n"); mysql_close(&mysql); } row = mysql_fetch_row(res); length = mysql_fetch_lengths(res); //得到img欄位資料的長度 mysql_close(&mysql); /*寫入檔案*/ fp = fopen(filename, "wb"); if (!fp) { mysql_free_result(res); mysql_close(&mysql); printf("建立檔案失敗\n"); return; } fwrite(row[0], 1, length[0], fp); //這裡千萬不能用strlen計算長度,因為檔案中可能有很多結束標誌字元'\0' fclose(fp); mysql_free_result(res); mysql_close(&mysql); printf("讀取成功\n"); }
我開始被 strlen 的問題搞得暈頭轉向,心想不用 strlen 那我再用什麼得到長度呢,還好後來找到了 mysql_fetch_lengths 這個函式。