存储大文件
概述
在本指南中,您将学习如何通过使用 GridFS 在 MongoDB 中存储和检索大文件。GridFS 存储系统在存储文件时会将文件分割成块,并在检索时重新组装这些文件。GridFS 的驱动程序实现是一个抽象层,用于管理文件存储的操作和组织。
如果您的任何文件大小超过 16 MB 的 BSON 文档大小限制,请使用 GridFS。有关 GridFS 是否适合您用例的更详细信息,请参阅GridFS MongoDB 服务器手册。
GridFS 的工作原理
GridFS 将文件组织在 存储桶 中,存储桶是一组包含文件块及其描述信息的 MongoDB 集合。存储桶包含以下集合
chunks
:存储二进制文件块files
:存储文件元数据
当您首次向驱动器写入数据时,如果该桶不存在,驱动器会创建GridFS桶。该桶包含以默认桶名fs
为前缀的chunks
和files
集合,除非您指定了不同的名称。为了确保高效检索文件和相关元数据,驱动器会在每个集合上创建一个索引。在GridFS桶上执行读取和写入操作之前,驱动器确保这些索引存在。
有关GridFS索引的更多信息,请参阅MongoDB服务器手册中的GridFS Indexes。
当使用GridFS存储文件时,驱动器会将文件拆分为更小的块,每个块由chunks
集合中的一个单独文档表示。它还在files
集合中创建一个文档,其中包含文件ID、文件名和其他文件元数据。
以下图表显示了GridFS在将文件上传到桶时如何拆分文件

在检索文件时,GridFS从指定桶中的files
集合中检索元数据,并使用这些信息从chunks
集合中的文档重新构建文件。
创建GridFS桶
要开始使用GridFS存储或检索文件,请创建一个新的GridFSBucket
实例,并传入一个代表您的数据库的IMongoDatabase
对象。此方法访问现有桶或创建一个新桶(如果不存在)。
以下示例为db
数据库创建一个新的GridFSBucket
实例
var client = new MongoClient("<connection string>"); var database = client.GetDatabase("db"); // Creates a GridFS bucket or references an existing one var bucket = new GridFSBucket(database);
自定义桶
您可以通过将GridFSBucketOptions
类的实例传递给GridFSBucket()
构造函数来自定义GridFS存储桶配置。以下表格描述了GridFSBucketOptions
类中的属性。
字段 | 描述 |
---|---|
| 用于文件和块集合的前缀的存储桶名称。默认值为 数据类型: |
| GridFS将文件分割成的块大小。默认值为255 KB。 数据类型: |
| 用于存储桶操作的读取关注点。默认值是数据库的读取关注点。 数据类型: ReadConcern |
| 用于存储桶操作的读取偏好。默认值是数据库的读取偏好。 数据类型: ReadPreference |
| 用于存储桶操作的写入关注点。默认值是数据库的写入关注点。 数据类型: WriteConcern |
以下示例通过将GridFSBucketOptions
类的实例传递给GridFSBucket()
构造函数,创建了一个名为"myCustomBucket"
的bucket。
var options = new GridFSBucketOptions { BucketName = "myCustomBucket" }; var customBucket = new GridFSBucket(database, options);
上传文件
您可以使用以下方法将文件上传到GridFS bucket。
OpenUploadStream()
或OpenUploadStreamAsync()
:打开一个新上传流,您可以写入文件内容。UploadFromStream()
或UploadFromStreamAsync()
:将现有流的内容上传到GridFS文件。
以下部分描述了如何使用这些方法。
写入上传流
使用 OpenUploadStream()
或 OpenUploadStreamAsync()
方法创建指定文件名的上传流。这些方法接受以下参数:
参数 | 描述 |
---|---|
| 要上传的文件名。 数据类型: |
| 可选。 一个 数据类型: GridFSUploadOptions |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例演示了如何通过以下步骤打开上传流:
调用
OpenUploadStream()
方法打开名为"my_file"
的可写 GridFS 流调用
Write()
方法将数据写入my_file
调用
Close()
方法关闭指向my_file
的流
选择同步 或 异步 选项卡以查看相应的代码
using (var uploader = bucket.OpenUploadStream("my_file")) { // ASCII for "HelloWorld" byte[] bytes = { 72, 101, 108, 108, 111, 87, 111, 114, 108, 100 }; uploader.Write(bytes, 0, bytes.Length); uploader.Close(); }
using (var uploader = await bucket.OpenUploadStreamAsync("my_file", options)) { // ASCII for "HelloWorld" byte[] bytes = { 72, 101, 108, 108, 111, 87, 111, 114, 108, 100 }; await uploader.WriteAsync(bytes, 0, bytes.Length); await uploader.CloseAsync(); }
要自定义上传流配置,将 GridFSUploadOptions
类的实例传递给 OpenUploadStream()
或 OpenUploadStreamAsync()
方法。GridFSUploadOptions
类包含以下属性:
属性 | 描述 |
---|---|
| 每个批次中上传的块数。默认值为 16 MB 除以 数据类型: |
| 除了最后一个块的大小较小外,每个块的大小。默认值为255 KB。 数据类型: |
|
以下示例执行了前面示例中的相同步骤,但还使用了 ChunkSizeBytes
选项来指定每个块的大小。选择 同步 或 异步 选项卡以查看相应的代码。
var options = new GridFSUploadOptions { ChunkSizeBytes = 1048576 // 1 MB }; using (var uploader = bucket.OpenUploadStream("my_file", options)) { // ASCII for "HelloWorld" byte[] bytes = { 72, 101, 108, 108, 111, 87, 111, 114, 108, 100 }; uploader.Write(bytes, 0, bytes.Length); uploader.Close(); }
var options = new GridFSUploadOptions { ChunkSizeBytes = 1048576 // 1 MB }; using (var uploader = await bucket.OpenUploadStreamAsync("my_file", options)) { // ASCII for "HelloWorld" byte[] bytes = { 72, 101, 108, 108, 111, 87, 111, 114, 108, 100 }; await uploader.WriteAsync(bytes, 0, bytes.Length); await uploader.CloseAsync(); }
上传现有流
使用 UploadFromStream()
或 UploadFromStreamAsync()
方法将流的内容上传到新的 GridFS 文件。这些方法接受以下参数
参数 | 描述 |
---|---|
| 要上传的文件名。 数据类型: |
| 读取文件内容的流。 数据类型: Stream |
| 可选。 一个 数据类型: GridFSUploadOptions |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例演示了如何通过以下步骤打开上传流:
以二进制读取模式打开位于
/path/to/input_file
的文件作为流调用
UploadFromStream()
方法,将流的内容写入名为"new_file"
的 GridFS 文件
选择 同步 或 异步 选项卡,查看相应的代码。
using (var fileStream = new FileStream("/path/to/input_file", FileMode.Open, FileAccess.Read)) { bucket.UploadFromStream("new_file", fileStream); }
using (var fileStream = new FileStream("/path/to/input_file", FileMode.Open, FileAccess.Read)) { await bucket.UploadFromStreamAsync("new_file", fileStream); }
下载文件
您可以使用以下方法从 GridFS 存储桶下载文件
OpenDownloadStream()
或OpenDownloadStreamAsync()
:打开一个新的下载流,您可以从该流中读取文件内容DownloadToStream()
或DownloadToStreamAsync()
:将 GridFS 文件的内容写入现有的流
以下各节更详细地描述了这些方法。
从下载流读取
使用 OpenDownloadStream()
或 OpenDownloadStreamAsync()
方法创建下载流。这些方法接受以下参数
参数 | 描述 |
---|---|
| 要下载的文件的 数据类型: BsonValue |
| 可选。 一个 数据类型: GridFSDownloadOptions |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例展示了如何通过以下步骤打开下载流:
获取名为
"new_file"
的 GridFS 文件的_id
值调用
OpenDownloadStream()
方法并将_id
值传递以将文件作为可读 GridFS 流打开创建一个
buffer
向量以存储文件内容调用
Read()
方法从downloader
流读取文件内容到向量
选择 同步 或 异步 选项卡,查看相应的代码。
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var doc = bucket.Find(filter).FirstOrDefault(); if (doc != null) { using (var downloader = bucket.OpenDownloadStream(doc.Id)) { var buffer = new byte[downloader.Length]; downloader.Read(buffer, 0, buffer.Length); // Process the buffer as needed } }
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var cursor = await bucket.FindAsync(filter); var fileInfoList = await cursor.ToListAsync(); var doc = fileInfoList.FirstOrDefault(); if (doc != null) { using (var downloader = await bucket.OpenDownloadStreamAsync(doc.Id)) { var buffer = new byte[downloader.Length]; await downloader.ReadAsync(buffer, 0, buffer.Length); // Process the buffer as needed } }
要自定义下载流配置,将 GridFSDownloadOptions
类的实例传递给 OpenDownloadStream()
方法。GridFSDownloadOptions
类包含以下属性:
属性 | 描述 |
---|---|
| 指示流是否支持 seeking(定位),即在流中查询和更改当前位置的能力。默认值是 数据类型: |
以下示例与上一个示例执行相同的步骤,但还设置了Seekable
选项为true
以指定流是可寻址的。
选择 同步 或 异步 选项卡,查看相应的代码。
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var doc = bucket.Find(filter).FirstOrDefault(); if (doc != null) { var options = new GridFSDownloadOptions { Seekable = true }; using (var downloader = bucket.OpenDownloadStream(id, options)) { var buffer = new byte[downloader.Length]; downloader.Read(buffer, 0, buffer.Length); // Process the buffer as needed } }
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var cursor = await bucket.FindAsync(filter); var fileInfoList = await cursor.ToListAsync(); var doc = fileInfoList.FirstOrDefault(); if (doc != null) { var options = new GridFSDownloadOptions { Seekable = true }; using (var downloader = await bucket.OpenDownloadStreamAsync(doc.Id, options)) { var buffer = new byte[downloader.Length]; await downloader.ReadAsync(buffer, 0, buffer.Length); // Process the buffer as needed } }
下载到现有流
使用DownloadToStream()
或DownloadToStreamAsync()
方法将GridFS文件的内容下载到现有流。这些方法接受以下参数
参数 | 描述 |
---|---|
| 要下载的文件的 数据类型: BsonValue |
| 该流是.NET/C#驱动程序将GridFS文件下载到其中的流。此属性的值必须是实现 数据类型: Stream |
| 可选。 一个 数据类型: GridFSDownloadOptions |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例演示了如何通过执行以下操作将内容下载到现有流
以二进制写入模式打开位于
/path/to/output_file
的文件作为流获取名为
"new_file"
的 GridFS 文件的_id
值调用
DownloadToStream()
方法,并将_id
值传递以将"new_file"
的内容下载到流中
选择 同步 或 异步 选项卡,查看相应的代码。
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var doc = bucket.Find(filter).FirstOrDefault(); if (doc != null) { using (var outputFile = new FileStream("/path/to/output_file", FileMode.Create, FileAccess.Write)) { bucket.DownloadToStream(doc.Id, outputFile); } }
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var cursor = await bucket.FindAsync(filter); var fileInfoList = await cursor.ToListAsync(); var doc = fileInfoList.FirstOrDefault(); if (doc != null) { using (var outputFile = new FileStream("/path/to/output_file", FileMode.Create, FileAccess.Write)) { await bucket.DownloadToStreamAsync(doc.Id, outputFile); } }
查找文件
要在GridFS存储桶中查找文件,请在您的GridFSBucket
实例上调用Find()
或FindAsync()
方法。这些方法接受以下参数
参数 | 描述 |
---|---|
| 一个查询过滤器,用于指定在 数据类型: |
| 读取文件内容的流。 数据类型: Stream |
| 可选。一个 数据类型:GridFSFindOptions |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例展示了如何从GridFS存储桶中的文件检索并打印文件元数据。Find()
方法返回一个IAsyncCursor<GridFSFileInfo>
实例,您可以通过该实例访问结果。它使用一个foreach
循环遍历返回的游标,并显示上传文件示例中上传的文件的详细内容。
选择 同步 或 异步 选项卡,查看相应的代码。
var filter = Builders<GridFSFileInfo>.Filter.Empty; var files = bucket.Find(filter); foreach (var file in files.ToEnumerable()) { Console.WriteLine(file.ToJson()); }
{ "_id" : { "$oid" : "..." }, "length" : 13, "chunkSize" : 261120, "uploadDate" : { "$date" : ... }, "filename" : "new_file" } { "_id" : { "$oid" : "..." }, "length" : 50, "chunkSize" : 1048576, "uploadDate" : { "$date" : ... }, "filename" : "my_file" }
var filter = Builders<GridFSFileInfo>.Filter.Empty; var files = await bucket.FindAsync(filter); await files.ForEachAsync(file => Console.Out.WriteLineAsync(file.ToJson()))
{ "_id" : { "$oid" : "..." }, "length" : 13, "chunkSize" : 261120, "uploadDate" : { "$date" : ... }, "filename" : "new_file" } { "_id" : { "$oid" : "..." }, "length" : 50, "chunkSize" : 1048576, "uploadDate" : { "$date" : ... }, "filename" : "my_file" }
要自定义查找操作,将GridFSFindOptions
类的实例传递给Find()
或FindAsync()
方法。GridFSFindOptions
类包含以下属性
属性 | 描述 |
---|---|
| 结果的排序顺序。如果您没有指定排序顺序,该方法将按照它们插入的顺序返回结果。 数据类型: |
删除文件
要从GridFS存储桶中删除文件,请在您的GridFSBucket
实例上调用Delete()
或DeleteAsync()
方法。此方法会从您的存储桶中删除文件的元数据集合及其相关的数据块。
Delete
和DeleteAsync()
方法接受以下参数
参数 | 描述 |
---|---|
| 要删除的文件的 数据类型: BsonValue |
| 可选。 一个可以用来取消操作的令牌。 数据类型: CancellationToken |
以下代码示例展示了如何删除名为 "my_file"
的文件,通过传递其 _id
值给 delete_file()
使用
Builders
类创建一个匹配名为"my_file"
的文件的过滤器使用
Find()
方法查找名为"my_file"
的文件将文件的
_id
值传递给Delete()
方法以删除文件
选择 同步 或 异步 选项卡,查看相应的代码。
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var doc = bucket.Find(filter).FirstOrDefault(); if (doc != null) { bucket.Delete(doc.Id); }
var filter = Builders<GridFSFileInfo>.Filter.Eq(x => x.Filename, "new_file"); var cursor = await bucket.FindAsync(filter); var fileInfoList = await cursor.ToListAsync(); var doc = fileInfoList.FirstOrDefault(); if (doc != null) { await bucket.DeleteAsync(doc.Id); }
注意
文件修订版
Delete()
和 DeleteAsync()
方法一次只能删除一个文件。如果您想删除每个文件修订版,或者具有相同文件名但上传时间不同的文件,请收集每个修订版的 _id
值。然后,将每个 _id
值单独调用 Delete()
或 DeleteAsync()
方法。
API 文档
要了解更多关于此页面上使用的类的信息,请参阅以下 API 文档
要了解更多关于此页面上使用的 GridFSBucket
类的方法,请参阅以下 API 文档