1. 程式人生 > >沐浴晨風想一想,今天該怎樣努力;踏著夕陽問一問,今天學到了什麼。

沐浴晨風想一想,今天該怎樣努力;踏著夕陽問一問,今天學到了什麼。

直接把檔案放入資料庫中比較適合小檔案,方便管理,比如頭像圖片和聲音,如果是較大型的檔案建議不要直接存進資料庫,而是放在伺服器,把檔案索引放在資料庫。

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 這個函式。