Docs 菜单

存储大文件

在本指南中,您可以了解如何使用GridFS在 MongoDB 中存储和检索大文件。 GridFS 是 PyMongo 实现的规范,描述了如何在存储文件时将文件拆分为数据段,并在检索文件时重新组合文件。 GridFS 驱动程序的实现是一个管理文件存储操作和组织的抽象。

如果文件大小超过16 MB 的BSON文档大小限制,则应使用GridFS 。 有关GridFS是否适合您的使用案例的更多详细信息,请参阅MongoDB Server手册中的GridFS

以下部分描述了 GridFS 操作以及如何执行这些操作。

GridFS 在存储桶中组织文件,存储桶是一组包含文件数据段及其描述信息的MongoDB 集合。存储桶包含以下集合,使用 GridFS 规范中定义的约定命名:

  • chunks 集合存储二进制文件数据段。

  • files 集合存储文件元数据。

当您创建新的 GridFS 存储桶时,驱动程序会创建前面的集合,并以默认存储桶名称fs作为前缀,除非您指定其他名称。 驱动程序还会在每个集合上创建索引,以确保高效检索文件和相关元数据。 如果 GridFS 存储桶不存在,则驱动程序仅在执行第一次写入操作时才会创建该存储桶。 仅当索引不存在且存储桶为空时,驱动程序才会创建索引。 有关 GridFS 索引的更多信息,请参阅 MongoDB Server 手册中的GridFS 索引

使用 GridFS 存储文件时,驱动程序会将文件拆分成较小的数据块,每个数据块由 chunks 集合中的单独文档表示。它还在 files 集合中创建文档,其中包含文件 ID、文件名和其他文件元数据。您可以从内存或数据流上传文件。请参阅下图,了解 GridFS 在上传到存储桶时如何拆分文件。

A diagram that shows how GridFS uploads a file to a bucket

在检索文件时,GridFS 从指定存储桶上的 files 集合中获取元数据,并使用该信息通过 chunks 集合中的文档重建文件。您可以将文件读取到内存中,或者将其输出到流。

要从 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()方法。

要了解有关使用 PyMongo 存储和检索大文件的更多信息,请参阅以下 API 文档: