pymongo 利用gridfs構建大文件存儲系統

一、gridfs介紹

GridFS 用於存儲和恢復那些超過16M(BSON文件限制)的文件(如:圖片、音頻、視頻等),適合於不常改變但是經常需要連續訪問的大文件。

GridFS 也是文件存儲的一種方式,但是它是存儲在MonoDB的集合中。

GridFS 可以更好的存儲大於16M的文件。

GridFS 會將大文件對象分割成多個小的chunk(文件片段),一般爲256k/個,每個chunk將作爲MongoDB的一個文檔(document)被存儲在chunks集合中。

GridFS 用兩個集合來存儲一個文件:fs.files與fs.chunks。每個文件的實際內容被存在chunks(二進制數據)中,和文件有關的meta數據(filename,content_type,還有用戶自定義的屬性)將會被存在files集合中。如下,兩個圖分別是files和chunks的信息。其中,files中存儲文件的元信息,默認使用集合爲fs.files,除自定義鍵外,還需包含:

  • _id 主鍵

  • length 文件所包含的字節數

  • chunkSize 組成文件的每個塊的大小,單位爲字節,默認值爲256KB,可調整

  • uploadDate 文件被上傳到GridFS的日期

  • md5 文件內容的MD5校驗值,該值由服務器端測試得到

 其中,每一個文件存儲的各個chunk的files_id相同,如圖chunk4和5中files_id相同。

 

二、文件系統

import pymongo
from pymongo import MongoClient
from gridfs import GridFS
class GFS(object):
    def __init__(self, file_db,file_table):
        self.file_db = file_db
        self.file_table = file_table

    def createDB(self): #連接數據庫,並創建文件數據庫與數據表
        client = MongoClient('localhost',27017)
        db = client[self.file_db]
        file_table = db[self.file_table]
        return (db,file_table)

    def insertFile(self,db,filePath,query): #將文件存入數據表
        fs = GridFS(db,self.file_table)
        if fs.exists(query):
            print('已經存在該文件')
        else:
            with open(filePath,'rb') as fileObj:
                data = fileObj.read()
                ObjectId = fs.put(data,filename = filePath.split('/')[-1])
                print(ObjectId)
                fileObj.close()
            return ObjectId

    def getID(self,db,query): #通過文件屬性獲取文件ID,ID爲文件刪除、文件讀取做準備
        fs=GridFS(db, self.file_table)
        ObjectId=fs.find_one(query)._id
        return ObjectId

    def getFile(self,db,id): #獲取文件屬性,並讀出二進制數據至內存
        fs = GridFS(db, self.file_table)
        gf=fs.get(id)
        bdata=gf.read() #二進制數據
        attri={} #文件屬性信息
        attri['chunk_size']=gf.chunk_size
        attri['length']=gf.length
        attri["upload_date"] = gf.upload_date
        attri["filename"] = gf.filename
        attri['md5']=gf.md5
        print(attri)
        return (bdata, attri)

    # def listFile(self,db): #列出所有文件名
    #     fs = GridFS(db, self.file_table)
    #     gf = fs.list()

    # def findFile(self,db,file_table): #列出所有文件二進制數據
    #     fs = GridFS(db, table)
    #     for file in fs.find():
    #         bdata=file.read()

    def write_2_disk(self,bdata, attri): #將二進制數據存入磁盤
        name = "get_"+attri['filename']
        if name:
            output = open(name, 'wb')
        output.write(bdata)
        output.close()
        print("fetch image ok!")

    def remove(self,db,id): #文件數據庫中數據的刪除
        fs = GridFS(db, self.file_table)        
        fs.delete(id) #只能是id


if __name__=='__main__':
    gfs=GFS('fileDB','fileTable')
    (file_db,fileTable) = gfs.createDB() #創建數據庫與數據表
    filePath = 'C:/Users/Administrator/Desktop/02655.jpeg' #插入的文件
    query = {'filename': '02655.jpeg'}
    id=gfs.insertFile(file_db,filePath,query) #插入文件
    id=gfs.getID(file_db,query)
    (bdata,attri)=gfs.getFile(file_db,id) #查詢並獲取文件信息至內存
    gfs.write_2_disk(bdata,attri) #寫入磁盤
    # gfs.remove(file_db,id) #刪除數據庫中文件

經測試數據庫創建、插入、讀取、寫入磁盤和刪除都能正常工作。

三、總結

對於文件存入與讀寫至磁盤的操作較多,而對於如何刪除總結較少,fs的delete參數只能是文件id,因此文件id的獲取則成爲刪除操作的關鍵,本文通過getID函數獲取。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章