C#使用MongoDb來存儲文件


近期在寫一個小玩意,需要保存一些圖片,以前我采用的是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/

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM