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

在检索文件时,GridFS从指定bucket中的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()
的参数设置,如下面的代码示例所示
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
字段确定)。
或者,您可以使用接受文件_id
字段作为参数的open_download_stream()
方法
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 文档