存储大文件
Overview
在本指南中,您可以了解如何使用GridFS在 MongoDB 中存储和检索大文件。 GridFS 是 PyMongo 实现的规范,描述了如何在存储文件时将文件拆分为数据段,并在检索文件时重新组合文件。 GridFS 驱动程序的实现是一个管理文件存储操作和组织的抽象。
如果文件大小超过16 MB 的 BSON 文档大小限制,则应使用 GridFS。 有关 GridFS 是否适合您的使用案例的更多详细信息,请参阅 MongoDB Server 手册中的 GridFS 。
以下部分描述了 GridFS 操作以及如何执行这些操作。
GridFS 的工作原理
GridFS 在存储桶中组织文件,存储桶是一组包含文件数据段及其描述信息的MongoDB 集合。存储桶包含以下集合,使用 GridFS 规范中定义的约定命名:
chunks
集合存储二进制文件数据段。files
集合存储文件元数据。
当您创建新的 GridFS 存储桶时,驱动程序会创建前面的集合,并以默认存储桶名称fs
作为前缀,除非您指定其他名称。 驱动程序还会在每个集合上创建索引,以确保高效检索文件和相关元数据。 如果 GridFS 存储桶不存在,则驱动程序仅在执行第一次写入操作时才会创建该存储桶。 仅当索引不存在且存储桶为空时,驱动程序才会创建索引。 有关 GridFS 索引的更多信息,请参阅 MongoDB Server 手册中的GridFS 索引。
使用 GridFS 存储文件时,驱动程序会将文件拆分成较小的数据块,每个数据块由 chunks
集合中的单独文档表示。它还在 files
集合中创建文档,其中包含文件 ID、文件名和其他文件元数据。您可以从内存或数据流上传文件。请参阅下图,了解 GridFS 在上传到存储桶时如何拆分文件。

在检索文件时,GridFS 从指定存储桶上的 files
集合中获取元数据,并使用该信息通过 chunks
集合中的文档重建文件。您可以将文件读取到内存中,或者将其输出到流。
创建 GridFS 存储桶
要从 GridFS 存储或检索文件,请调用GridFSBucket()
构造函数并传入Database
实例,以创建 GridFS 存储桶。 您可以使用GridFSBucket
实例对存储桶中的文件调用读取和写入操作。
client = MongoClient("<connection string>") db = client["db"] bucket = gridfs.GridFSBucket(db)
要使用默认名称fs
以外的自定义名称创建或引用存储桶,请将存储桶名称作为第二个参数传递给GridFSBucket()
构造函数,如下所示:
custom_bucket = gridfs.GridFSBucket(db, bucket_name="myCustomBucket")
上传文件
使用GridFSBucket
类中的open_upload_stream()
方法为给定文件名创建上传流。 open_upload_stream()
方法允许您指定配置信息,如文件数据段大小和其他要作为元数据存储的字段/值对。 将这些选项设置为open_upload_stream()
的参数,如以下代码示例所示:
with bucket.open_upload_stream( "my_file", chunk_size_bytes=1048576, metadata={"contentType": "text/plain"} ) as grid_in: grid_in.write("data to store")
检索文件信息
在本部分中,您可以了解如何检索存储在 GridFS 存储桶的 files
集合的文件元数据。元数据包含所引用文件的相关信息,包括:
文件的
_id
文件的名称
文件的长度/大小
上传日期和时间
您可以在其中存储任何其他信息的
metadata
文档
要从GridFS存储桶检索文件,请对GridFSBucket
实例调用find()
方法。 该方法返回一个Cursor
实例,您可以从该实例访问权限结果。 要学习;了解有关PyMongo中Cursor
对象的更多信息,请参阅从游标访问数据。
以下代码示例向您展示如何从 GridFS 存储桶中的所有文件中检索和打印文件元数据。 它使用for...in
事务语法遍历Cursor
可迭代对象并显示结果:
for file_doc in bucket.find({}): print(file_doc)
find()
方法接受各种查询规范。 您可以使用其参数来指定排序顺序、要返回的最大文档数以及在返回之前要跳过的文档数。 要了解有关查询 MongoDB 的更多信息,请参阅检索数据。
下载文件
您可以使用 GridFSBucket
中的 open_download_stream_by_name()
方法创建下载流,从 MongoDB 数据库下载文件。
以下示例展示了如何下载文件名"my_file"
引用的文件并读取其内容:
file = bucket.open_download_stream_by_name("my_file") contents = file.read()
注意
如果存在多个具有相同 filename
值的文档,GridFS 将流式传输具有给定名称(由 uploadDate
字段决定)的最新文件。
或者可以使用 open_download_stream()
方法将文件的 _id
字段作为参数:
file = bucket.open_download_stream(ObjectId("66b3c86e672a17b6c8a4a4a9")) contents = file.read()
注意
GridFS 流媒体 API 无法加载部分数据段。 当下载流需要从 MongoDB 拉取一个数据段时,它会将整个数据段拉取到内存中。 255千字节的默认数据段大小通常已足够,但您可以减小数据段大小以减少内存开销。
重命名文件
使用 rename()
方法更新存储桶中 GridFS 文件的名称。您必须用文件的 _id
字段而不是文件名来指定要重命名的文件。
以下示例展示了如何通过引用文档的_id
字段将filename
字段更新为"new_file_name"
:
bucket.rename(ObjectId("66b3c86e672a17b6c8a4a4a9"), "new_file_name")
注意
rename()
方法一次仅支持更新一个文件的名称。 要重命名多个文件,请从存储桶中检索与文件名匹配的文件列表,从要重命名的文件中提取_id
字段,然后将每个值分别传递给rename()
方法。
删除文件
使用delete()
方法从存储桶中删除文件的集合文档和关联的数据段。 这实际上删除了该文件。 您必须用文件的_id
字段而不是文件名来指定文件。
下面的示例展示了如何通过引用文件的 _id
字段来删除文件:
bucket.delete(ObjectId("66b3c86e672a17b6c8a4a4a9"))
注意
delete()
方法一次仅支持删除一个文件。 要删除多个文件,请从存储桶中检索文件,提取要删除的文件中的_id
字段,然后将每个值分别传递给delete()
方法。
API 文档
要了解有关使用 PyMongo 存储和检索大文件的更多信息,请参阅以下 API 文档: