作為一個NoSql資料庫的代表,存取多媒體資料,應該是強項吧?那麼,圖檔在mongoDB裡是如何存取的呢?(其實,關系型資料庫存取圖檔也一點問題沒有,是以我看NoSql的強項不在于是否存儲多媒體,而在于采用鍵值對的方式來存儲資料。)
mongoDB存取圖檔有兩種方式:
"由于MongoDB的文檔結構為BJSON格式(BJSON全稱:Binary JSON),而BJSON格式本身就支援儲存二進制格式的資料,是以可以把檔案的二進制格式的資料直接儲存到MongoDB的文檔結構中。但是由于一個BJSON的最大長度不能超過4M,是以限制了單個文檔中能存入的最大檔案不能超過4M。為了提供對大容量檔案存取的支援,samus驅動提供了“GridFS”方式來支援,“GridFS”方式檔案操作需要引入新的程式集“MongoDB.GridFS.dll”。"
一、在文檔對象中存取檔案
當檔案大小較小的時候,直接存入文檔對象實作起來更簡潔。比如大量圖檔檔案的存取等,一般圖檔檔案都不會超過4M。我們先實作一個上傳圖檔存入資料庫,再取出來寫回頁面的例子:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using MongoDB.Bson;
using MongoDB.Driver;
namespace mongotest
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
Init();
}
//資料庫連接配接字元串
const string strconn = "mongodb://127.0.0.1:27017";
//資料庫名稱
const string dbName = "test";
MongoServer server;
MongoDatabase db;
void Init()
{
//建立資料庫連結
server = MongoDB.Driver.MongoServer.Create(strconn);
//獲得資料庫
db = server.GetDatabase(dbName);
}
private void SaveImgBJSON(byte[] byteImg)
{
BsonDocument doc = new BsonDocument();
doc["ID"] = 1;
doc["Img"] = byteImg;
MongoCollection col = db.GetCollection("thins");
col.Save(doc);
}
private void btnSaveImg_Click(object sender, EventArgs e)
{
byte[] byteImg = File.ReadAllBytes(@"c:\temp\yl.jpg");
SaveImgBJSON(byteImg);
}
private void btnShowImg_Click(object sender, EventArgs e)
{
MongoCollection col = db.GetCollection("thins");
var query = new QueryDocument { { "ID", 1} };
var result = col.FindAs<BsonDocument>(query);
byte[] buff = (byte[])((BsonDocument)result.ToList()[0]).GetValue("Img");
MemoryStream MS = new MemoryStream(buff);
pictureBox1.Image = Image.FromStream(MS);
}
}
}
二、用GridFS方式存取檔案
在實作GridFS方式前我先講講它的原理,為什麼可以存大檔案。驅動首先會在目前資料庫建立兩個集合:"fs.files"和"fs.chunks"集合,前者記錄了檔案名,檔案建立時間,檔案類型等基本資訊;後者分塊存儲了檔案的二進制資料(并支援加密這些二進制資料)。分塊的意思是把檔案按照指定大小分割,然後存入多個文檔中。"fs.files"怎麼知道它對應的檔案二進制資料在哪些塊呢?那是因為在"fs.chunks"中有個"files_id"鍵,它對應"fs.files"的"_id"。"fs.chunks"還有一個鍵(int型)"n",它表明這些塊的先後順序。這兩個集合名中的"fs"也是可以通過參數自定義的。
(我想起了Sql Server的FileStream)
如果你隻是想知道怎麼用,可以忽略上面這段話,下面将用法:
這裡引用了兩個第三方dll,可以到https://github.com/samus/mongodb-csharp下載下傳,編譯後得到。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using MongoDB;
using MongoDB.GridFS;
namespace mongotest
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
Init();
}
private void btnGridFSSave_Click(object sender, EventArgs e)
{
byte[] byteImg = File.ReadAllBytes(@"c:\temp\yl.jpg");
filename = GridFsSave(byteImg);
MessageBox.Show(filename);
}
private void btnGridFSShow_Click(object sender, EventArgs e)
{
byte[] buff = GridFsRead(filename);
MemoryStream MS = new MemoryStream(buff);
pictureBox1.Image = Image.FromStream(MS);
}
private Mongo mongo;
private IMongoDatabase test;
string filename;
void Init()
{
var connstr = @"Server=localhost:27017";
mongo = new Mongo(connstr);
mongo.Connect();
test = mongo["test"];
}
private string GridFsSave(byte[] byteFile)
{
string filename = Guid.NewGuid().ToString();
//這裡GridFile構造函數有個重載,bucket參數就是用來替換那個建立集合名中預設的"fs"的。
GridFile gridFile = new GridFile(test);
using (GridFileStream gridFileStream = gridFile.Create(filename))
{
gridFileStream.Write(byteFile, 0, byteFile.Length);
}
return filename;
}
private byte[] GridFsRead(string filename)
{
GridFile gridFile = new GridFile(test);
GridFileStream gridFileStream = gridFile.OpenRead(filename);
byte[] bytes = new byte[gridFileStream.Length];
gridFileStream.Read(bytes, 0, bytes.Length);
return bytes;
}
}
}
存儲在資料庫中如圖: