快速掌握mongoDB(五)——通过mongofiles和C#驱动操作GridFS
<h2>1 GridFS简介</h2><p> 当前Bson能存储的最大尺寸是16M,我们想把大于16M的文件存入mongoDB中怎么办呢?mongoDB提供的GridFS就是专门做这个的。使用GridFS存储大文件时,文件被分成一个个的块(默认大小是255 kb),将每一块存放在一个单独的document中。GridFS将文件存储在两个collection中:chunks collection和files collection,其中chunks collection保存文件块,files collection保存文件的元数据。</p>
<h2>2 使用mongofiles进行大文件管理</h2>
<p> mongofiles是mongoDB内置的文件操作工具,提供了十分简单的API让我们可以通过命令行实现文件的上传、下载、查找和删除。我们使用一个视频文件做测试。</p>
<h3>1 上传文件(put)</h3>
<p> 这里准备将/data/videos下的电影绿皮书(文件名:”lvpishu.mkv“)上传到mongoDB数据库myfiles中下,只需要使用一条命令就可以完成文件的上传:在mongoDb的bin目录下执行命令 <span class="cnblogs_code">mongofiles -d myfiles -l /data/videos/lvpishu.mkv put lvpishu.mkv ----host 192.168.70.131:27017</span> ,如果标明--host的话默认上传到localhost。上传完成后使用robomongo查看文件信息,如下:</p>
<p><img style="border: 2px solid rgba(0, 0, 255, 1)" src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713114142470-1818069124.png" alt=""></p>
<p> 使用robomongo查看上传的文件信息,如下图:</p>
<p><img style="border: 2px solid rgba(0, 0, 255, 1)" src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713131239208-920824653.png" alt=""></p>
<h3>2 下载文件(get)</h3>
<p> 下载GridFS中的文件使用命令Get,如我们要将刚才上传的电影,下载到/data/videos2目录下,执行命令 <span class="cnblogs_code">mongofiles -d myfiles -l /data/videos2/lvpishu.mkv <span style="color: rgba(0, 0, 255, 1)">get</span> lvpishu.mkv</span> 即可,效果如下:</p>
<p><img src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713123923256-1760237483.png" alt=""></p>
<h3>3 查找文件(list、search)</h3>
<p> 查询 GridFS中的文件可以使用search查询文件名包含某字符串的文件信息,使用list查询以某字符串开头的文件列表,因为我们只上传了一个文件所以这里的文件列表也只展示一条文件信息,执行命令效果如下:</p>
<p> <img style="border: 2px solid rgba(0, 0, 255, 1)" src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713125208388-1378178772.png" alt=""></p>
<h3>4 删除文件(delete)</h3>
<p> 如果我们想删除GridFS中的某一文件,使用delete <filename>命令</p>
<p><img style="border: 2px solid rgba(0, 0, 255, 1)" src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713124606854-1713058226.png" alt=""></p>
<h2>3 使用C#驱动操作GridFS</h2>
<p> 前边我们已经使用mongoDB自带的命令行工具mongofiles实现了大文件的增删查操作,但是实际开发中我们更常用的方式是使用各种语言驱动来管理文件,这里展示怎么通过C#驱动来实现大文件的管理。添加GridFS的包 <span class="cnblogs_code">Install-Package MongoDB.Driver.GridFS</span> ,C#驱动中提供了GridFSBucket(GridFS桶)对象来保存文件,它是fs.files和fs.chunks的组合,我们在使用时,最好使用GridFSBucket来和GridFS交互,尽量不要直接使用底层的fs.files和fs.chunks)。</p>
<p> C#驱动mongoDB的上传和下载文件有两种形式:①通过字节数组byte[]上传和下载,这种方式适用于文件不大的情况,②使用stream的方式进行上传和下载,这种形式适用于各种场合,这里就采用stream的形式做文件的上传和下载演示,代码如下:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
{
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连接数据库</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> client = <span style="color: rgba(0, 0, 255, 1)">new</span> MongoClient(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mongodb://192.168.70.133:27017, 192.168.70.131:27017, 192.168.70.129:27017</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取database</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> mydb = client.GetDatabase(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">myfilesDb</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">初始化GridFSBucket</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> bucket = <span style="color: rgba(0, 0, 255, 1)">new</span> GridFSBucket(mydb, <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GridFSBucketOptions
{
BucketName </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">lvpishu</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置根节点名</span>
ChunkSizeBytes = <span style="color: rgba(128, 0, 128, 1)">1024</span> * <span style="color: rgba(128, 0, 128, 1)">1024</span>, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置块的大小为1M</span>
WriteConcern = WriteConcern.WMajority, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">写入确认级别为majority</span>
ReadPreference = ReadPreference.Secondary<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">优先从从节点读取</span>
<span style="color: rgba(0, 0, 0, 1)"> });
</span><span style="color: rgba(255, 0, 0, 1)"><strong><span style="font-size: 14px">//上传文件
</span></strong></span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">上传的配置项,可以添加文件元数据</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> options = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GridFSUploadOptions
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ChunkSizeBytes = 1048000, </span>
Metadata = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BsonDocument
{
{ </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">format</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mkv</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> },
{ </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">country</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">USA</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> }
}
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过stream形式上传文件</span>
<span style="color: rgba(0, 0, 0, 1)"> ObjectId fileId;
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">开始文件上传----------------></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">string</span> sourceFile = <span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">D:\迅雷下载\lvpishu.mkv</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> fs = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileStream(sourceFile, FileMode.Open))
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">mongodb中的文件名为“绿皮书”</span>
Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">上传中...</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
fileId </span>= bucket.UploadFromStream(filename: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">绿皮书</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, source: fs, options: options);
}
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"><----------------文件上传完成</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.WriteLine();
</span><strong><span style="font-size: 14px; color: rgba(255, 0, 0, 1)">//查看文件</span></strong>
<span style="color: rgba(0, 0, 255, 1)">var</span> filter = Builders<GridFSFileInfo><span style="color: rgba(0, 0, 0, 1)">.Filter;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> cursor = bucket.Find(filter.Eq(x => x.Filename, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">绿皮书</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)))
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> fileInfo =<span style="color: rgba(0, 0, 0, 1)"> cursor.FirstOrDefault();
fileId </span>=<span style="color: rgba(0, 0, 0, 1)"> fileInfo.Id;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件名:{fileInfo?.Filename}, 文件大小:{fileInfo?.Length}字节, 文件上传时间:{fileInfo?.UploadDateTime.AddHours(8)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">自定义的元数据:{fileInfo?.Metadata}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine();
</span><strong><span style="font-size: 14px; color: rgba(255, 0, 0, 1)">//下载文件
</span></strong><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">文件下载的位置</span>
Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">开始文件下载----------------></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">string</span> tagrgetPath = <span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">D:/mongoDownLoad/绿皮书下载.mkv</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> mongoStream =<span style="color: rgba(0, 0, 0, 1)"> bucket.OpenDownloadStream(id: fileId))
{
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">下载中...</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过FileStream写文件</span>
<span style="color: rgba(0, 0, 255, 1)">using</span> (FileStream fsWrite = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileStream(tagrgetPath, FileMode.Create))
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开辟临时缓存内存</span>
<span style="color: rgba(0, 0, 255, 1)">byte</span>[] buffer = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[<span style="color: rgba(128, 0, 128, 1)">1024</span> * <span style="color: rgba(128, 0, 128, 1)">1024</span><span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">readCount是真正读取到的字节数</span>
<span style="color: rgba(0, 0, 255, 1)">int</span> readCount = mongoStream.Read(buffer, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, buffer.Length);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">写入目标文件</span>
fsWrite.Write(buffer, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, readCount);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断是否读取完成</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (readCount <<span style="color: rgba(0, 0, 0, 1)"> buffer.Length)
{
</span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
}
}
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">最好比较一下mongodb中的文件和下载文件的Md5值,如果md5相同表示下载完成
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里为了简单起见,就简单判断以下文件是否存在</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (File.Exists(<span style="color: rgba(128, 0, 0, 1)">@"</span><span style="color: rgba(128, 0, 0, 1)">D:/mongoDownLoad/绿皮书下载.mkv</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
{
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"><----------------文件下载完成!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine();
</span><span style="color: rgba(255, 0, 0, 1)"><strong><span style="font-size: 14px">//删除文件</span></strong></span>
<span style="color: rgba(0, 0, 0, 1)"> bucket.Delete(id: fileId);
Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件已删除!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ReadKey();
}
}</span></pre>
</div>
<p> 初始化GridFSBucket时可以设置一些参数:BucketName用于设置files和chunks的根节点名,如设置BucketName="lvpishu",那么在数据库中保存文件的两个collection的名字为lvpishu.files和lvpishu.chunks。ChunkSizeBytes用于设置数据块的大小,这里设置数据块大小为1M。</p>
<p>代码的注释比较详细,这里就不多介绍了,程序运行结果如下:</p>
<p><img style="border: 2px solid rgba(0, 0, 255, 1)" src="https://img2018.cnblogs.com/blog/1007918/201907/1007918-20190713161609074-1730687194.png" alt=""></p>
<p><strong>小结 </strong> </p>
<p> 本节介绍了GridFS的概念,并简单演示了怎样使用mongofile和C#驱动进行大文件的上传、查询、下载、删除操作。如果文中有错误的话,希望大家可以指出,我会及时修改,谢谢!</p>
<p> </p>
<p> </p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<div style="border: 2px solid #21759b; padding: 20px">
<div>作者:捞月亮的猴子</div>
<div>出处:https://www.cnblogs.com/wyy1234/</div>
<div>欢迎转载,但请标明出处。如果本文对您有些许帮助,点击一下推荐吧,Thanks♪(・ω・)ノ</div>
</div><br><br>
来源:https://www.cnblogs.com/wyy1234/p/11048130.html
頁:
[1]