zoukankan      html  css  js  c++  java
  • C# 玩转MongoDB(三)

    前面两篇文章,已经讲解了C#对MongoDB的基本操作以及小文件的读写存储,那么对于大型(>=16M)文件呢?具体又该如何操作呢,本文主要以一个简单的小例子,简述C#如何通过GridFS进行MongoDB的大文件的操作,仅供学习分享使用,如有不足之处,还请指正。

    什么是GridFS?

    在实现GridFS方式前我先讲讲它的原理,为什么可以存大文件。驱动首先会在当前数据库创建两个集合:"fs.files"和"fs.chunks"集合,前者记录了文件名,文件创建时间,文件类型等基本信息;后者分块存储了文件的二进制数据(并支持加密这些二进制数据)。分块的意思是把文件按照指定大小分割,然后存入多个文档中。"fs.files"怎么知道它对应的文件二进制数据在哪些块呢?那是因为在"fs.chunks"中有个"files_id"键,它对应"fs.files"的"_id"。"fs.chunks"还有一个键(int型)"n",它表明这些块的先后顺序。这两个集合名中的"fs"也是可以通过参数自定义的。

    GridFS存储原理

    一个文件存储在两个集合中,一个用于存储元数据(文件名称,类型,大小等内容,可便于索引),一个用于存储真实二进制数据(分块存储),如下所示:

     GridFS安装

    如果需要存储大型文件,则需要安装GridFS插件,如下所示:

    项目--右键--管理Nuget程序包--打卡Nuget包管理器--浏览搜索MongoDB.Driver.GridFS--安装。如下所示:

    示例截图

    首先是文件的查询,如下所示:

    文件的新增

     核心代码

    本示例主要是在MongoDB中进行文件的操作,所以之前的MongoHelper已不再适用,本例新增了文件专用帮助类MongoFileHelper,如下所示:

      1 using MongoDB.Bson;
      2 using MongoDB.Driver;
      3 using MongoDB.Driver.GridFS;
      4 using System;
      5 using System.Collections.Generic;
      6 using System.IO;
      7 using System.Linq;
      8 using System.Text;
      9 using System.Threading.Tasks;
     10 
     11 namespace DemoMongo.Common
     12 {
     13 
     14     public class MongoFileHelper
     15     {
     16 
     17         private string connStr = "mongodb://127.0.0.1:27017";//服务器网址
     18 
     19         private string dbName = "hexdb";//数据库名称
     20 
     21         private IMongoClient client;//连接客户端
     22 
     23         private IMongoDatabase db;//连接数据库
     24 
     25         private string collName;//集合名称
     26 
     27         public MongoFileHelper()
     28         {
     29 
     30         }
     31 
     32         public MongoFileHelper(string connStr, string dbName, string collName)
     33         {
     34             this.connStr = connStr;
     35             this.dbName = dbName;
     36             this.collName = collName;
     37             this.Init();
     38         }
     39 
     40         /// <summary>
     41         /// 初始化连接客户端
     42         /// </summary>
     43         private void Init()
     44         {
     45             if (client == null)
     46             {
     47                 client = new MongoClient(this.connStr);
     48             }
     49             if (db == null)
     50             {
     51                 db = client.GetDatabase(this.dbName);
     52             }
     53         }
     54 
     55         /// <summary>
     56         /// 通过字节方式上传
     57         /// </summary>
     58         /// <param name="filePath"></param>
     59         public void UploadFile(string filePath)
     60         {
     61             IGridFSBucket bucket = new GridFSBucket(db);
     62             byte[] source = File.ReadAllBytes(filePath);
     63             string fileName = Path.GetFileName(filePath);
     64             var options = new GridFSUploadOptions
     65             {
     66                 ChunkSizeBytes = 64512, // 63KB
     67                 Metadata = new BsonDocument
     68                 {
     69                     { "resolution", "1080P" },
     70                     { "copyrighted", true }
     71                 }
     72             };
     73             var id = bucket.UploadFromBytes(fileName, source);
     74             //返回的ID,表示文件的唯一ID
     75 
     76 
     77         }
     78 
     79         /// <summary>
     80         /// 通过Stream方式上传
     81         /// </summary>
     82         /// <param name="filePath"></param>
     83         public void UploadFile2(string filePath)
     84         {
     85             IGridFSBucket bucket = new GridFSBucket(db);
     86             var stream = new FileStream(filePath, FileMode.Open);
     87 
     88             string fileName = Path.GetFileName(filePath);
     89             var options = new GridFSUploadOptions
     90             {
     91                 ChunkSizeBytes = 64512, // 63KB
     92                 Metadata = new BsonDocument
     93                 {
     94                     { "resolution", "1080P" },
     95                     { "copyrighted", true }
     96                 }
     97             };
     98             var id = bucket.UploadFromStream(fileName, stream);
     99             //返回的ID,表示文件的唯一ID
    100 
    101 
    102         }
    103 
    104         /// <summary>
    105         /// 通过字节写入到流
    106         /// </summary>
    107         /// <param name="filePath"></param>
    108         public void UploadFile3(string filePath)
    109         {
    110             IGridFSBucket bucket = new GridFSBucket(db);
    111             byte[] source = File.ReadAllBytes(filePath);
    112             string fileName = Path.GetFileName(filePath);
    113             var options = new GridFSUploadOptions
    114             {
    115                 ChunkSizeBytes = 64512, // 63KB
    116                 Metadata = new BsonDocument
    117                 {
    118                     { "resolution", "1080P" },
    119                     { "copyrighted", true }
    120                 }
    121             };
    122             using (var stream = bucket.OpenUploadStream(fileName, options))
    123             {
    124                 var id = stream.Id;
    125                 stream.Write(source, 0, source.Length);
    126                 stream.Close();
    127             }
    128         }
    129 
    130         /// <summary>
    131         /// 下载文件
    132         /// </summary>
    133         /// <param name="id"></param>
    134         public void DownloadFile(ObjectId id,string filePath)
    135         {
    136             IGridFSBucket bucket = new GridFSBucket(db);
    137             byte[] source = bucket.DownloadAsBytes(id);
    138             //返回的字节内容
    139             //var bytes = await bucket.DownloadAsBytesAsync(id);
    140             using (Stream stream = new FileStream(filePath, FileMode.OpenOrCreate)) {
    141                 stream.Write(source, 0, source.Length);
    142             }
    143         }
    144 
    145         public void DownloadFile2(ObjectId id)
    146         {
    147             IGridFSBucket bucket = new GridFSBucket(db);
    148             Stream destination = null;
    149             bucket.DownloadToStream(id, destination);
    150             //返回的字节内容
    151             //await bucket.DownloadToStreamAsync(id, destination);
    152 
    153         }
    154 
    155         public void DownloadFile3(ObjectId id)
    156         {
    157             IGridFSBucket bucket = new GridFSBucket(db);
    158             Stream destination = null;
    159             using (var stream = bucket.OpenDownloadStream(id))
    160             {
    161                 // read from stream until end of file is reached
    162                 stream.Close();
    163             }
    164         }
    165 
    166         public void DownloadFile4(string fileName)
    167         {
    168             IGridFSBucket bucket = new GridFSBucket(db);
    169             var bytes = bucket.DownloadAsBytesByName(fileName);
    170 
    171             // or
    172 
    173             Stream destination = null;
    174             bucket.DownloadToStreamByName(fileName, destination);
    175 
    176             // or
    177 
    178             using (var stream = bucket.OpenDownloadStreamByName(fileName))
    179             {
    180                 // read from stream until end of file is reached
    181                 stream.Close();
    182             }
    183         }
    184 
    185         public List<MongoFile> FindFiles()
    186         {
    187             IGridFSBucket bucket = new GridFSBucket(db);
    188             var filter = Builders<GridFSFileInfo>.Filter.And(
    189                 //Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, string.Empty),
    190                 Builders<GridFSFileInfo>.Filter.Gte(x => x.UploadDateTime, new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
    191                 Builders<GridFSFileInfo>.Filter.Lt(x => x.UploadDateTime, new DateTime(2022, 2, 1, 0, 0, 0, DateTimeKind.Utc)));
    192             var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime);
    193             var options = new GridFSFindOptions
    194             {
    195                 //Limit = 1,
    196                 Sort = sort
    197             };
    198             List<MongoFile> lstFiles = new List<MongoFile>();
    199             using (var cursor = bucket.Find(filter, options))
    200             {
    201                 var fileInfos = cursor.ToList();
    202                 foreach (var fileInfo in fileInfos) {
    203                     MongoFile f = new MongoFile()
    204                     {
    205                          Id=fileInfo.Id,
    206                          name = fileInfo.Filename,
    207                          suffix = Path.GetExtension(fileInfo.Filename),
    208                         size = int.Parse(fileInfo.Length.ToString())
    209                     };
    210                     lstFiles.Add(f);
    211                 }
    212             }
    213             return lstFiles;
    214         }
    215 
    216         public List<MongoFile> FindFileByName(string fileName)
    217         {
    218             IGridFSBucket bucket = new GridFSBucket(db);
    219             var filter = Builders<GridFSFileInfo>.Filter.And(
    220                 Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, fileName),
    221                 Builders<GridFSFileInfo>.Filter.Gte(x => x.UploadDateTime, new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc)),
    222                 Builders<GridFSFileInfo>.Filter.Lt(x => x.UploadDateTime, new DateTime(2015, 2, 1, 0, 0, 0, DateTimeKind.Utc)));
    223             var sort = Builders<GridFSFileInfo>.Sort.Descending(x => x.UploadDateTime);
    224             var options = new GridFSFindOptions
    225             {
    226                 //Limit = 1,
    227                 Sort = sort
    228             };
    229             List<MongoFile> lstFiles = new List<MongoFile>();
    230             using (var cursor = bucket.Find(filter, options))
    231             {
    232                 var fileInfos = cursor.ToList();
    233                 foreach (var fileInfo in fileInfos)
    234                 {
    235                     MongoFile f = new MongoFile()
    236                     {
    237                         Id = fileInfo.Id,
    238                         name = fileInfo.Filename,
    239                         suffix = Path.GetExtension(fileInfo.Filename),
    240                         size = int.Parse(fileInfo.Length.ToString())
    241                     };
    242                     lstFiles.Add(f);
    243                 }
    244             }
    245             return lstFiles;
    246         }
    247     }
    248 }

    然后操作时,调用帮助类即可,如下所示:

    查询调用

     1        private void btnQuery_Click(object sender, EventArgs e)
     2         {
     3             string name = this.txtName.Text.Trim();
     4             List<MongoFile> fileInfos = new List<MongoFile>();
     5             if (string.IsNullOrEmpty(name))
     6             {
     7                 fileInfos = helper.FindFiles();
     8             }
     9             else {
    10                 fileInfos = helper.FindFileByName(name);
    11             }
    12             
    13             this.dgView.AutoGenerateColumns = false;
    14             this.bsView.DataSource = fileInfos;
    15             this.dgView.DataSource = this.bsView;
    16         }

    下载调用

     1         private void dgView_CellContentClick(object sender, DataGridViewCellEventArgs e)
     2         {
     3             if (e.ColumnIndex == 3) {
     4                 //第3个是下载按钮
     5                 SaveFileDialog sfd = new SaveFileDialog();
     6                 
     7                 var file = (MongoFile)(this.dgView.Rows[e.RowIndex].DataBoundItem);
     8                 sfd.FileName = file.name;
     9                 sfd.Title = "请保存文件";
    10                 if (DialogResult.OK == sfd.ShowDialog())
    11                 {
    12                     helper.DownloadFile(file.Id,sfd.FileName);
    13                     MessageBox.Show("保存成功");
    14 
    15                 }
    16             }
    17         }

    保存调用

     1         private void btnSave_Click(object sender, EventArgs e)
     2         {
     3             string filePath = this.txtPath.Text;
     4             if (!string.IsNullOrEmpty(filePath))
     5             {
     6                 this.helper.UploadFile(filePath);
     7                 MessageBox.Show("保存成功");
     8             }
     9             else {
    10                 MessageBox.Show("请先选择文件");
    11             }
    12             
    13         }

    MongoDB查询

    当通过GridFS方式保存文件成功后,会在GridFS Buckets下生成fs对象,且在集合下生成两个集合【fs.files,fs.chunks】,用于存储文件,如下所示:

     通过查询fs.files集合,可以查找上传文件的列表,如下所示:

     通过查询fs.chunks集合,可以查询文件的内容(二进制数据),如下所示:

     注意:如果文件太大,在fs.chunks集合中,进行分片存储,n表示存储的顺序。

     以上就是C#操作MongoDB大文件存储的相关内容,旨在抛砖引玉,共同进步。

    备注

    点绛唇·感兴

    【朝代】宋代 【作者】王禹偁【chēng】

    雨恨云愁,江南依旧称佳丽。水村渔市,一缕孤烟细。
    天际征鸿,遥认行如缀。平生事,此时凝睇,谁会凭栏意。(栏 通:阑)


    作者:Alan.hsiang
    出处:http://www.cnblogs.com/hsiang/
    本文版权归作者和博客园共有,写文不易,支持原创,欢迎转载【点赞】,转载请保留此段声明,且在文章页面明显位置给出原文连接,谢谢。
    关注个人公众号,定时同步更新技术及职场文章

  • 相关阅读:
    MVC之Servlet控制器(二)
    MVC之Servlet控制器(一)
    基于Java实现批量下载网络图片
    @ModelAttribute运用详解
    MyBatis
    理解RESTful架构
    并行计算结课论文边写边总结2
    并行计算结课论文边写边总结(1)
    CUDA笔记(六)
    ubuntu12.04
  • 原文地址:https://www.cnblogs.com/hsiang/p/15391520.html
Copyright © 2011-2022 走看看