存储大文件
Overview
在本指南中,您可以学习;了解如何使用GridFS在MongoDB中存储和检索大文件。 GridFS存储系统在存储文件时将文件拆分为数据段,并在检索文件时重新组合这些文件。 GridFS驱动程序的实施是一个抽象,用于管理文件存储的操作和组织。
如果任何文件的大小超过16 MB 的BSON文档大小限制,请使用GridFS 。有关GridFS是否适合您的使用案例的更多详细信息,请参阅MongoDB Server手册中的 GridFS 。
GridFS 的工作原理
GridFS 在存储桶中组织文件,存储桶是一组包含文件数据段及其描述信息的MongoDB 集合。存储桶包含了以下集合:
chunks
:存储二进制文件段files
:存储文件元数据
当您首次向 GridFS 存储桶写入数据时,驾驶员会创建GridFS存储桶(如果尚不存在)。存储桶包含以默认存储桶名称 fs
为前缀的 chunks
和 files
集合,除非您指定了其他名称。为了确保有效检索文件和相关元数据,驾驶员会在每个集合上创建一个索引。在对GridFS存储桶执行写入操作之前,驾驶员会确保这些索引存在。
有关GridFS索引的更多信息,请参阅MongoDB Server手册中的GridFS索引。MongoDB Server
使用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。 数据类型: |
| 用于存储桶操作的读关注(read concern)。默认值为数据库的读关注(read concern)。 |
| 用于存储桶操作的读取偏好(read preference)。默认值为数据库的读取偏好(read preference)。 数据类型:ReadPreference |
| 用于存储桶操作的写关注(write concern)。默认值为数据库的写关注(write concern)。 数据类型:写关注 |
以下示例通过将 GridFSBucketOptions
类的实例传递给 GridFSBucket()
构造函数来创建名为 "myCustomBucket"
的存储桶:
var options = new GridFSBucketOptions { BucketName = "myCustomBucket" }; var customBucket = new GridFSBucket(database, options);
上传文件
您可以使用以下方法将文件上传到GridFS存储桶:
OpenUploadStream()
或OpenUploadStreamAsync()
:打开新的上传流,您可以向其中写入文件内容UploadFromStream()
或UploadFromStreamAsync()
:将现有流的内容上传到GridFS文件
以下部分介绍如何使用这些方法。
写入上传流
使用 OpenUploadStream()
或 OpenUploadStreamAsync()
方法为给定文件名创建上传流。这些方法接受以下参数:
Parameter | 说明 |
---|---|
| 要上传的文件的名称。 数据类型: |
| 可选。指定上传流配置的 |
| 可选。可用于取消操作的令牌。 |
此代码示例演示如何通过执行以下步骤来打开上传流:
调用
OpenUploadStream()
方法为名为"my_file"
的文件打开可写GridFS流调用
Write()
方法以写入my_file
调用
Close()
方法关闭指向my_file
的流
选择 Synchronous 或 Asynchronous标签页以查看相应的代码:
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
选项指定每个数据段的数据块。选择 Synchronous 或 Asynchronous标签页以查看相应的代码。
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文件。这些方法接受以下参数:
Parameter | 说明 |
---|---|
| 要上传的文件的名称。 数据类型: |
| |
| 可选。指定上传流配置的 |
| 可选。可用于取消操作的令牌。 |
此代码示例演示如何通过执行以下步骤来打开上传流:
以二进制读取模式将位于
/path/to/input_file
的文件作为流打开调用
UploadFromStream()
方法将流的内容写入名为"new_file"
的GridFS文件
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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()
方法创建下载流。这些方法接受以下参数:
Parameter | 说明 |
---|---|
| 要下载的文件的 |
| 可选。指定下载流配置的 |
| 可选。可用于取消操作的令牌。 |
以下代码示例演示了如何通过执行以下步骤来打开下载流:
检索名为
"new_file"
的GridFS文件的_id
值调用
OpenDownloadStream()
方法并传递_id
值以将文件作为可读GridFS流打开创建一个
buffer
向量来存储文件内容调用
Read()
方法将文件内容从downloader
流读入向量
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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
类包含以下属性:
属性 | 说明 |
---|---|
| 指示流是否支持查找、查询和更改流中当前位置的能力。默认值为 数据类型: |
以下示例执行与前面的示例相同的步骤,但还将 Seekable
选项设置为 true
以指定该流是可查找的。
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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文件的内容下载到现有流。这些方法接受以下参数:
Parameter | 说明 |
---|---|
| 要下载的文件的 |
| |
| 可选。指定下载流配置的 |
| 可选。可用于取消操作的令牌。 |
以下代码示例演示了如何通过执行以下操作来下载到现有流:
以二进制写入模式将位于
/path/to/output_file
的文件作为流打开检索名为
"new_file"
的GridFS文件的_id
值调用
DownloadToStream()
方法并传递_id
值,以将"new_file"
的内容下载到流
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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()
方法。这些方法接受以下参数:
Parameter | 说明 |
---|---|
| 查询过滤,用于指定 数据类型: |
| |
| 可选。 |
| 可选。可用于取消操作的令牌。 |
以下代码示例演示如何从GridFS存储桶中的文件检索和打印文件元数据。Find()
方法返回一个IAsyncCursor<GridFSFileInfo>
实例,您可以从该实例访问权限结果。它使用foreach
循环遍历返回的游标,并显示上传文件示例中上传的文件的内容。
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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()
方法接受以下参数:
Parameter | 说明 |
---|---|
| 要删除的文件的 |
| 可选。可用于取消操作的令牌。 |
以下代码示例展示了如何将名为 "my_file"
的文件的 _id
值传递给 delete_file()
来删除该文件:
使用
Builders
类创建与名为"my_file"
的文件匹配的过滤使用
Find()
方法查找名为"my_file"
的文件将文件的
_id
值传递给Delete()
方法以删除文件
选择 Synchronous 或 Asynchronous 标签页,查看相应的代码。
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文档: