1 GridFS簡介
當前Bson能儲存的最大尺寸是16M,我們想把大於16M的檔案存入mongoDB中怎麼辦呢?mongoDB提供的GridFS就是專門做這個的。使用GridFS儲存大檔案時,檔案被分成一個個的塊(預設大小是255 kb),將每一塊存放在一個單獨的document中。GridFS將檔案儲存在兩個collection中:chunks collection和files collection,其中chunks collection儲存檔案塊,files collection儲存檔案的後設資料。
2 使用mongofiles進行大檔案管理
mongofiles是mongoDB內建的檔案操作工具,提供了十分簡單的API讓我們可以通過命令列實現檔案的上傳、下載、查詢和刪除。我們使用一個視訊檔案做測試。
1 上傳檔案(put)
這裡準備將/data/videos下的電影綠皮書(檔名:”lvpishu.mkv“)上傳到mongoDB資料庫myfiles中下,只需要使用一條命令就可以完成檔案的上傳:在mongoDb的bin目錄下執行命令 mongofiles -d myfiles -l /data/videos/lvpishu.mkv put lvpishu.mkv 。上傳完成後使用robomongo檢視檔案資訊,如下:
使用robomongo檢視上傳的檔案資訊,如下圖:
2 下載檔案(get)
下載GridFS中的檔案使用命令Get,如我們要將剛才上傳的電影,下載到/data/videos2目錄下,執行命令 mongofiles -d myfiles -l /data/videos2/lvpishu.mkv get lvpishu.mkv 即可,效果如下:
3 查詢檔案(list、search)
查詢 GridFS中的檔案可以使用search查詢檔名包含某字串的檔案資訊,使用list查詢以某字串開頭的檔案列表,因為我們只上傳了一個檔案所以這裡的檔案列表也只展示一條檔案資訊,執行命令效果如下:
4 刪除檔案(delete)
如果我們想刪除GridFS中的某一檔案,使用delete <filename>命令
3 使用C#驅動操作GridFS
前邊我們已經使用mongoDB自帶的命令列工具mongofiles實現了大檔案的增刪查操作,但是實際開發中我們更常用的方式是使用各種語言驅動來管理檔案,這裡展示怎麼通過C#驅動來實現大檔案的管理。新增GridFS的包 Install-Package MongoDB.Driver.GridFS ,C#驅動中提供了GridFSBucket(GridFS桶)物件來儲存檔案,它是fs.files和fs.chunks的組合,我們在使用時,最好使用GridFSBucket來和GridFS互動,儘量不要直接使用底層的fs.files和fs.chunks)。
C#驅動mongoDB的上傳和下載檔案有兩種形式:①通過位元組陣列byte[]上傳和下載,這種方式適用於檔案不大的情況,②使用stream的方式進行上傳和下載,這種形式適用於各種場合,這裡就採用stream的形式做檔案的上傳和下載演示,程式碼如下:
class Program { static void Main(string[] args) { //連線資料庫 var client = new MongoClient("mongodb://192.168.70.133:27017, 192.168.70.131:27017, 192.168.70.129:27017"); //獲取database var mydb = client.GetDatabase("myfilesDb"); //初始化GridFSBucket var bucket = new GridFSBucket(mydb, new GridFSBucketOptions { BucketName = "lvpishu", //設定根節點名 ChunkSizeBytes = 1024 * 1024, //設定塊的大小為1M WriteConcern = WriteConcern.WMajority, //寫入確認級別為majority ReadPreference = ReadPreference.Secondary //優先從從節點讀取 }); //上傳檔案 //上傳的配置項,可以新增檔案後設資料 var options = new GridFSUploadOptions { //ChunkSizeBytes = 1048000, Metadata = new BsonDocument { { "format", "mkv" }, { "country", "USA" } } }; //通過stream形式上傳檔案 ObjectId fileId; Console.WriteLine("開始檔案上傳---------------->"); string sourceFile = @"D:\迅雷下載\lvpishu.mkv"; using (var fs = new FileStream(sourceFile, FileMode.Open)) { //mongodb中的檔名為“綠皮書” Console.WriteLine("上傳中..."); fileId = bucket.UploadFromStream(filename: "綠皮書", source: fs, options: options); } Console.WriteLine("<----------------檔案上傳完成"); Console.WriteLine(); //檢視檔案 var filter = Builders<GridFSFileInfo>.Filter; using (var cursor = bucket.Find(filter.Eq(x => x.Filename, "綠皮書"))) { var fileInfo = cursor.FirstOrDefault(); fileId = fileInfo.Id; Console.WriteLine($"檔名:{fileInfo?.Filename}, 檔案大小:{fileInfo?.Length}位元組, 檔案上傳時間:{fileInfo?.UploadDateTime.AddHours(8)}"); Console.WriteLine($"自定義的後設資料:{fileInfo?.Metadata}"); } Console.WriteLine(); //下載檔案 //檔案下載的位置 Console.WriteLine("開始檔案下載---------------->"); string tagrgetPath = @"D:/mongoDownLoad/綠皮書下載.mkv"; using (var mongoStream = bucket.OpenDownloadStream(id: fileId)) { Console.WriteLine("下載中..."); //通過FileStream寫檔案 using (FileStream fsWrite = new FileStream(tagrgetPath, FileMode.Create)) { //開闢臨時快取記憶體 byte[] buffer = new byte[1024 * 1024]; while (true) { //readCount是真正讀取到的位元組數 int readCount = mongoStream.Read(buffer, 0, buffer.Length); //寫入目標檔案 fsWrite.Write(buffer, 0, readCount); //判斷是否讀取完成 if (readCount < buffer.Length) { break; } } } } //最好比較一下mongodb中的檔案和下載檔案的Md5值,如果md5相同表示下載完成 //這裡為了簡單起見,就簡單判斷以下檔案是否存在 if (File.Exists(@"D:/mongoDownLoad/綠皮書下載.mkv")) { Console.WriteLine("<----------------檔案下載完成!"); } Console.WriteLine(); //刪除檔案 bucket.Delete(id: fileId); Console.WriteLine("檔案已刪除!"); Console.ReadKey(); } }
初始化GridFSBucket時可以設定一些引數:BucketName用於設定files和chunks的根節點名,如設定BucketName="lvpishu",那麼在資料庫中儲存檔案的兩個collection的名字為lvpishu.files和lvpishu.chunks。ChunkSizeBytes用於設定資料塊的大小,這裡設定資料塊大小為1M。
程式碼的註釋比較詳細,這裡就不多介紹了,程式執行結果如下:
小結
本節介紹了GridFS的概念,並簡單演示了怎樣使用mongofile和C#驅動進行大檔案的上傳、查詢、下載、刪除操作。如果文中有錯誤的話,希望大家可以指出,我會及時修改,謝謝!