近期在寫一個小玩意,需要保存一些圖片,以前我采用的是FTP或者直接數據庫保存文件,用FTP來保存文件感覺比較麻煩,用數據庫吧,還要改字段類型,修改代碼,修改查詢語句,懶得改。
以前看過mongonDb的文章,隨就打算用Mongon來存儲文件,然后打算百度一下看看,C#操作mongoDb的文章,全是互相抄襲,而且年代久遠,很多東西mongoDb都沒有了,隨就魔法上網。
不在介紹MongoDb是什么,怎么安裝,具體百度
一:使用前准備
1:安裝MongoDb,百度安裝 ,並下載任意一個mongonDb的可視化軟件
我mongoDb是裝在的linux服務器上,具體的安裝平台有讀者自己決定
可視乎軟件我推薦Robo
2:新建一個winfrom項目
右鍵項目Nuget包管理器,下載
安裝這兩個包
二:文件上傳
這里先用圖片來做測試
mongonDb有2種方式來存儲,1:普通的document來存儲文件,最大為16MB,2:gridFs存儲,
1:普通document存儲
示例代碼
引用命名空間
using MongoDB.Bson; using MongoDB.Driver;
定義數據庫名和地址字
private string connStr = "mongodb://xx.93.232.xx:27017"; private string dbName = "xxxx"; private IMongoDatabase database;
獲得dataBase
var client = new MongoClient(connStr); if (client != null) { database = client.GetDatabase(dbName); bucket = new GridFSBucket(database); //這個是初始化gridFs存儲的 }
創建文檔集合
private void CheckAddCreateCollection(string collectionName) { var collectionList = database.ListCollections().ToList(); var collectionNames = new List<string>(); //獲得所有集合的名稱 collectionList.ForEach(x => { collectionNames.Add(x["name"].AsString); }); //如果沒有這個集合就創建一個 (相當於創建一個表) if (!collectionNames.Contains(collectionName)) { database.CreateCollection(collectionName); } }
寫一個關於圖片信息的類,這里就用用戶頭像來表示了
public class UserAvatar { public int AvatarId { get; set; } public byte[] Avatar { get; set; } }
如果你感到疑惑為什么要創建一個類呢,因為mongon的任何crud操作都需要一個
IMongoCollection<TDocument>
的類型來進行操作。可以理解成ef中DbSet<xxxx>
獲取前面創建好的集合
private IMongoCollection<UserAvatar> GetUserCollection(string name) { return database.GetCollection<UserAvatar>(name); //傳入集合的名字 }
讀取圖片的字節流
var bytes = File.ReadAllBytes(@"C:\Users\哈哈哈\Desktop\test.jpg");
向mogoDb插入一條數據
private async Task< bool> AddAvater(UserAvatar avatar, IMongoCollection<UserAvatar> userAvatar) { await userAvatar.InsertOneAsync(avatar); //插入一條數據
//一下代碼是判斷了是否插入成功。 var result = userAvatar.AsQueryable().Where(x => x.AvatarId == avatar.AvatarId).Select(x => new UserAvatar { Avatar = x.Avatar, AvatarId = x.AvatarId }).ToList(); if (result.Count > 0) { this.textBox1.Text = result[0].AvatarId.ToString(); return true; } return false; }
讓我們到robo里面看看是否插入成功了。
可以看到有數據了
從MogoDb取出一條數據
private Task<UserAvatar> GetUserAvatar(int avatarId,string collectionName) { var task = Task.Run(() => { var userAvatar = GetUserCollection(collectionName); var result = userAvatar.AsQueryable().Where(x => x.AvatarId == avatarId).Select(x => new UserAvatar { Avatar = x.Avatar, AvatarId = x.AvatarId }).ToList(); if (result.Count > 0) { return result[0]; } return null; }); return task; }
為什么上面的代碼不在where后面直接toList呢?
答:MongoDb在文檔里面會自動添加一個_id的字段,這個時候反序列話,就不會成功了,報異常id不匹配。
讓我們來看下效果
顯示圖片的代碼
private void ShowImage(byte[] imageBytes) { pictureBox1.Image = null; MemoryStream memoryStream = new MemoryStream(imageBytes); Image image = Image.FromStream(memoryStream); Bitmap bitMap = new Bitmap(image, new Size(pictureBox1.Width, pictureBox1.Height)); pictureBox1.Image = bitMap; }
看看數據庫圖片ID為95的在不在。
2:grifFs存儲文件。按照Mongodb最新的文檔來說,基本上百度到一些C#使用gridFs來存儲文件的文章已經沒有用用了。
根據Mongon文檔的介紹,GirdF是用來存儲大於16m的文件。
GridFS是一種存儲大於最大文檔大小(目前為16MB)的二進制信息的方法。當您將文件上傳到GridFS時,文件會分成多個塊並上傳各個塊。從GridFS下載文件時,將從塊中重新組合原始內容。
初始化
private GridFSBucket bucket; bucket = new GridFSBucket(database);
根據官方文檔說明,GridFS文件使用兩個集合存儲在數據庫中,通常稱為“fs.files”和“fs.chunks”。上傳到GridFS的每個文件在“fs.files”集合中都有一個文檔,其中包含有關該文件的信息以及“fs.chunks”集合中用於存儲文件內容的必要數量的塊。
GridFS“bucket”是“fs.files”和“fs.chunks”集合的組合,它們共同代表可以存儲GridFS文件的存儲桶。
GridFSBucket
對象是表示一個GridFS的桶的根對象。
可以看來使用GirdFSBucket來管理所有的文件。
上傳文件非常的簡單
var id = bucket.UploadFromBytes("filename", source); //source字節數組 var id = await bucket.UploadFromBytesAsync("filename", source);
如果上傳成功我們就會在robo中可以看到在collection分組下面會出現
fs.chunks,和fs.files兩個集合
先看看fs.files里面存儲了
其中objectId,就是上面上傳代碼返回值,toString之后的結果,
下載文件 通過id來下載
public Task<byte[]> DownLoadFileFromGirdFs(ObjectId id) { return bucket.DownloadAsBytesAsync(id); }
如果不知道Id怎么辦?
就要先查找文件了用文件名,上傳時間呀也可以來查找
我是用文件名來查找的。如果你要問用那個objectId可以不可以查找?
可以很清楚的告訴你,我沒有實驗成功,直接就會報異常,給我報Unable to determine the serialization information(無法確定的序列化信息)
查找代碼
public ObjectId GetUploadFileId(string fileName) { var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, fileName); //eq方法,就是等於,還有其他的方法,具體看Mongo的api文檔 var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime); //按上傳時間來倒敘一下 var options = new GridFSFindOptions { Limit = 1, Sort = sort }; using (var cursor = bucket.Find(filter,options)) { var fileInfo = cursor.ToList().FirstOrDefault(); if (fileInfo != null && fileInfo.Length > 0) { return fileInfo.Id; } return new ObjectId(); } }
現在來結合下下載與查找代碼來看下效果
private async void button5_Click(object sender, EventArgs e) { var id = GetUploadFileId("yemobaiAvatar"); byte[] imageBytes= await DownLoadFileFromGirdFs(id); ShowImage(imageBytes); }
結果
最后附上官方文檔地址 http://mongodb.github.io/mongo-csharp-driver/