zoukankan      html  css  js  c++  java
  • MongoDb GridFS的使用

    MongoDb GridFS 是MongoDB的文件存储方案,主要用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频等),对大文件有着更好的性能。

    要在C#中使用GridFS,首先安装Nuget包: MongoDB.Driver.GridFS

    Bucket

    GridFS中的数据也是分集合存储的,每个集合叫一个bucket,每个bucket里面可以存储多个文件:

    在C#中使用bucket和使用集合差不多,创建一个GridFSBucket对象即可。

    var bucket = new GridFSBucket(db, new GridFSBucketOptions()
    {
        BucketName     = "my_bucket",
        ChunkSizeBytes = 256 * 1024, //
    块大小

    });

    对于bucket,主要的参数就是bucket名称和块大小,它也不用手动创建,在使用的时候会自动创建。

     

    上传数据

    对于byte[]数组,可以直接使用UploadFromBytes上传:

    var data = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray();
    var id = bucket.UploadFromBytes("filename", data);

    主要参数是传入一个文件名(文件名并不要求唯一,同一bucket类可以重复),返回数据id。

    也可以带入metadata信息。

    var options = new GridFSUploadOptions
    {
        Metadata = new BsonDocument
        {
            {"resolution""1080P"},
            {"copyrighted"true}
        },
        DisableMD5 = true,
    };
    var id   = bucket.UploadFromBytes("filename", data, options);

    上传Stream

    使用UploadFromBytes上传的时候,需要将上传的数据全部读取到内存,如果需要上传的是较大的文件,这种方式并不合适。此时可以使用UploadFromStream函数上传。

    using (var fs = File.OpenRead(@"r:123.jpg"))
    {
        bucket.UploadFromStream("123.jpg", fs);
    }

    也可以使用OpenUploadStream的方式打开为一个Stream,然后通过推的方式完成上传。

    using (var fs = File.OpenRead(@"r:123.jpg"))
    using (var upload = bucket.OpenUploadStream("123.jpg"))
    {
        fs.Copy(upload);
        upload.Close();
        Console.WriteLine(upload.Id);
    }

    注意:这个stream必须手动Close,只是调用Dispose不会写入到bucket中去。不知道算不算MongoDB API的一个bug。另外,GridFS的这个GridFSUploadStream.Close是通过隐藏的方式实现的,如果将他转换成了Stream使用,此时调用Close不能上传至GridFS,需要将其转换成GridFSUploadStream才行。

    下载:

    下载的API和上传类似,如下是几个基本示例:

    var id = new ObjectId("5b6ba04c77850928a438b1b2");
    var bytes = bucket.DownloadAsBytes(id);

    using (var target = File.Create(@"r: arget.jpg"))
    {
        bucket.DownloadToStream(id, target);
    }

    using (var download = bucket.OpenDownloadStream(id))
    using (var target = File.Create(@"r: arget.jpg"))
    {
        download.CopyTo(target);
    }

    查询:

    GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。对于bucket中的记录,实际上存成了两个部分。

    • 文件的实际内容被存在chunks(二进制数据)中,拆分成了一堆chunk存储
    • 相关的描述信息files集合中,它是一个标准的mongodb的文档模型,其结构为:
    {
      "_id" : <ObjectId>,
      "length" : <num>,
      "chunkSize" : <num>,
      "uploadDate" : <timestamp>,
      "md5" : <hash>,
      "filename" : <string>,
      "contentType" : <string>,
      "aliases" : <string array>,
      "metadata" : <any>,
    }
    gridfs对filename 和uploadDate字段做了索引的,通过它们查询能获取到较好的性能。

    参考文档: https://docs.mongodb.com/manual/core/gridfs/

    gridfs的api中封装了对它的查询,也是遵循标准的查询API的

    var filter = new {filename = "123.jpg"};
    var result = bucket.Find(filter.ToBsonDocument()).ToList();

    另外,也可以直接操作fs.files集合。

    var files = db.GetCollection<BsonDocument>("my_bucket.files");

    更新:

    GridFS的API支持对文档重命名:

    bucket.Rename(id, "NewName");
    

    但没有找打更新MetaData的API,在网上找了一下,有人已经提了这个问题。结论是目前官方没有封装,不过可以从fs.files集合中直接更新metadata。示例如下。

    var files = db.GetCollection<BsonDocument>("my_bucket.files");

    var filter = new BsonDocument()
    {
        ["_id"] = id
    };
    var update = new BsonDocument()
    {
        ["$set"] = new BsonDocument()
        {
            ["metadata"] = metaData
        }
    };

    files.UpdateOne(filter, update);

    小结

    Gridfs的API封装还算好用的,就是不过不知道为什么没有封装对描述信息的更新操作。官方文档链接如下,要深入学习的可以查看一下。

    本文这里主要介绍的是GridFS的使用,但需要注意的是,GridFS本身并不是分布式存储服务,它仍然依赖于MongoDB,并不是解决大规模的分布式存储的问题的,需要大容量存储和负载均衡等场景建议还是交给FastDFS等专业的服务来。

    不过,对于一些性能和容量要求不高的企业应用,存储一些图片,附件等小规模存储场景,还是非常合适的。部署和使用都是非常方便快捷的。

    另外,网上也有一些深入点介绍GridFS的文档,也可以看下。

  • 相关阅读:
    js 自定义事件
    django项目mysite
    python web 框架
    Python web-Http
    numpy学习
    django 中单独执行py文件修改用户名
    python解决排列组合
    解决Database returned an invalid datetime value. Are time zone definitions for your database installed?
    Anaconda下载地址
    Django中使用geetest实现滑动验证
  • 原文地址:https://www.cnblogs.com/TianFang/p/9452437.html
Copyright © 2011-2022 走看看