前言

由于项目需求,需要将识别的人脸图片存储到服务器的数据库中,经过了解得知目前业界存储图片主要有两种方式:

  1. 图片存储在磁盘上,即服务器文件系统中,数据库字段中保存的是图片的路径。
  2. 图片以二进制形式直接存储到数据库中(一般来说数据库会提供一个二进制字段来存储二进制数据。比如mysql中blob类型,容量64K或mediumblob类型,容量16M,longblob类型,容量4G)

对于两种方式各自的优缺点可以看这篇文章——>关于图片或者文件在数据库的存储方式归纳
总而言之:
1.图片以二进制形式存储在数据库

优点:
备份的时候方便,直接备份数据库,图片也跟着备份。换句话说,迁移环境的时候是方便。而图片放在磁盘上的话,数据库中存储的只是图片路径。备份数据库后,磁盘上的图片也要跟着备份才行。

缺点:
图片尽量不要存储在数据库中(是指不要二进制形式保存到字段,而只保存图片的路径)。这样的大字段数据会加重数据库的负担,拖慢数据库。在大并发访问的情况下很重要。

2.数据库中保存图片路径

优点:
数据库中保存的是图片路径的话,在web开发环境下,有个好处就是可以使用cdn加速(CDN优势及何时选择使用CDN)。
数据库字段中保存的是类似于这样子的”images/2020/12/15/ 1343287394783.jpg”。原来上传的图片文件名称会重新命名保存,比如按照时间戳来生成,这样子是为了避免文件名重复,网站的并发访问量越大,目录的生成分得越细越好。

缺点:
数据迁移不够方便,操作系统对单个目录的文件数量是有限制的。当文件数量很多的时候。从目录中获取文件的速度就会越来越慢。所以为了保持速度,需要使用固定规则将图片分散到多个目录中去。

因此可以根据具体情况选择图片存储的方案,由于本项目实际并不会有很大的并发访问量,因此我是选择直接将图片以二进制形式存储到MySQL数据库中。

正文

1.accountInfo.properties文件中存取数据库的连接信息

host=139.9.149.237
user=root
passwd=123456
db=Momo
charset=utf8

2.PropertiesUtil.py文件是一个加载配置文件的工具类,用于读取property配置文件中的数据库信息

# encoding: utf-8
'''
@author: niko
@contact: simaqingsheng@gmail.com
@file: PropertiesUtil.py
@time: 2020/3/30 12:19
@desc:
'''

# 加载配置文件工具类
class Properties(object):
    def __init__(self, fileName):
        self.fileName = fileName
        self.properties = {}

    def __getDict(self, strName, dictName, value):

        if (strName.find('.') > 0):
            k = strName.split('.')[0]
            dictName.setdefault(k, {})
            return self.__getDict(strName[len(k) + 1:], dictName[k], value)
        else:
            dictName[strName] = value
            return

    def getProperties(self):
        try:
            pro_file = open(self.fileName, 'Ur')
            for line in pro_file.readlines():
                line = line.strip().replace('\n', '')
                if line.find("#") != -1:
                    line = line[0:line.find('#')]
                if line.find('=') > 0:
                    strs = line.split('=')
                    strs[1] = line[len(strs[0]) + 1:]
                    self.__getDict(strs[0].strip(), self.properties, strs[1].strip())
        except Exception as e:
            raise e
        else:
            pro_file.close()
        return self.properties

3.SavePicToMysql.py文件用于将图片存储至数据库中

# encoding: utf-8
'''
@author: niko
@contact: simaqingsheng@gmail.com
@file: SavePicToMysql.py
@time: 2020/3/30 17:43
@desc:
'''

# 功能:将图片转成字节流存储到MySQL数据库
import pymysql

imgPath="face_picture/1.png"
# 读取图片文件
fp = open(imgPath, 'rb')
img = fp.read()
fp.close()

# 建立一个MySQL连接(不使用配置文件,直接填入数据库连接信息)
conn = pymysql.connect(host='139.9.149.237', user="root", passwd="123456", db="Momo",charset='utf8')

# 创建游标,给数据库发送sql指令,face_table中id已经设置为自增
cursor = conn.cursor()

try:
    # 创建数据库表
    cursor.execute('create table if not  exists face_table(id varchar(55)primary key , imageName varchar(50),'
                   'imageData mediumblob)ENGINE=InnoDB CHARSET=utf8; ')
except Exception as e:
    print(e)
    print("table create failed")
else:
    print("table create success")

try:
    sql = "INSERT INTO face_table(id,imageName,imageData) VALUES  (%s, %s, %s);"
    imageName = imgPath.split('/')[1]
    args = ("id_"+imageName,imageName, img)
    cursor.execute(sql, args)
except Exception as e:
    print(e)
else:
    print("插入图片成功!")

conn.commit()
# 关闭游标
cursor.close()
# 关闭数据库连接
conn.close()

4.ReadPicFromMysql.py文件用于从远程数据库中读取图片

# encoding: utf-8
'''
@author: niko
@contact: simaqingsheng@gmail.com
@file: ReadPicFromMysql.py
@time: 2020/3/30 19:12
@desc:
'''

import pymysql
from PropertiesUtil import Properties

#使用配置文件获取数据库连接信息
info = Properties("./resource/accountInfo.properties").getProperties()
host=info['host'] #主机ip地址
user=info['user']#用户名
passwd=info['passwd']#密码
db=info['db']#数据库名
charset=info['charset']#字符集

conn = pymysql.connect(host=host, user=user, passwd=passwd, db=db,charset=charset)

# 创建游标, 给数据库发送sql指令
cur = conn.cursor()
cur.execute("select * from face_table")
rows=cur.fetchall()#二维tuple

# 读取数据库所有图片
for row in rows:
    imageName=row[1]
    with open(imageName, 'wb') as fout:
        fout.write(row[2])

cur.close()
conn.close()

后记

注意如果是连接自己云服务器的Mysql数据库的话,一定注意在安全组中放行mysql的3306端口