存储大文件
概述
在本指南中,您可以学习如何使用 GridFS 在 MongoDB 中存储和检索大文件。GridFS 是由 C 驱动程序实现的一个规范,它描述了在存储时如何将文件分割成块,以及在检索时如何重新组装它们。驱动程序对 GridFS 的实现是一个抽象,它管理文件存储的操作和组织。
如果您的文件大小超过 16MB 的 BSON 文档大小限制,请使用 GridFS。有关 GridFS 是否适合您的用例的更详细信息,请参阅GridFS MongoDB 服务器手册。
GridFS 的工作原理
GridFS 以 桶 的形式组织文件,桶是一组包含文件块及其描述信息的 MongoDB 集合。该桶包含以下集合,使用 GridFS 规范中定义的约定命名
的
chunks
集合存储二进制文件块。files
集合存储文件元数据。
当您执行第一个写入操作时,如果 GridFS 桶不存在,驱动程序将创建该桶。桶包含前面提到的集合,并以默认桶名称 fs
前缀,除非您指定了不同的名称。为了确保高效检索文件及其相关元数据,如果这些集合不存在且桶为空,驱动程序还会在每个集合上创建索引。
有关 GridFS 索引的更多信息,请参阅 MongoDB 服务器手册中的 GridFS 索引。
当使用GridFS存储文件时,驱动程序会将文件分割成更小的块,每个块由chunks
集合中的一个单独的文档表示。它还在files
集合中创建一个文档,该文档包含文件ID、文件名和其他文件元数据。您可以通过传递一个流到C驱动程序以消耗它或创建一个新流并直接写入它来上传文件。
以下图显示了当文件上传到存储桶时GridFS如何分割文件

当您从GridFS检索文件时,它会从指定存储桶的files
集合中获取元数据,并使用这些信息从chunks
集合中的文档重新构建文件。您可以通过将文件内容写入现有流或创建一个指向文件的流来读取文件。
创建GridFS存储桶
要使用GridFS,首先调用mongoc_gridfs_bucket_new()
函数。此函数创建一个新的mongoc_gridfs_bucket_t
结构或访问现有的mongoc_gridfs_bucket_t
,并接受以下参数
数据库:指定创建存储桶的数据库
选项文档:指定用于自定义存储桶的选项,或
NULL
读取偏好:指定用于读取操作的读取偏好,或
NULL
以继承数据库的读取偏好错误位置:指定错误值的存储位置,或
NULL
以下示例调用mongoc_gridfs_bucket_new()
函数并将数据库作为参数传递
mongoc_database_t *db = mongoc_client_get_database (client, "db"); bson_error_t error; if (!mongoc_gridfs_bucket_new (db, NULL, NULL, &error)) { fprintf (stderr, "Failed to create bucket: %s\n", error.message); }
自定义存储桶
您可以通过将指定选项值的BSON文档传递给mongoc_gridfs_bucket_new()
函数来自定义GridFS存储桶配置。以下表格描述了您可以在文档中设置的选项
选项 | 描述 |
---|---|
bucketName | 指定用于文件和块集合的前缀的存储桶名称。默认值为 "fs" 。类型: string |
chunkSizeBytes | 指定GridFS将文件拆分的块大小。默认值为255 kB。 类型: int32 |
readConcern | 指定用于存储桶操作的读取关注点。默认值是数据库的读取关注点。 类型: mongoc_read_concern_t |
writeConcern | 指定用于存储桶操作的写入关注点。默认值是数据库的写入关注点。 类型: mongoc_write_concern_t |
以下示例通过向mongoc_gridfs_bucket_new()
传递一个设置bucketName
选项的选项文档来创建名为"myCustomBucket"
的存储桶
mongoc_database_t *db = mongoc_client_get_database (client, "db"); bson_t opts = BSON_INITIALIZER; BSON_APPEND_UTF8 (&opts, "bucketName", "myCustomBucket"); bson_error_t error; if (!mongoc_gridfs_bucket_new (db, &opts, NULL, &error)) { fprintf (stderr, "Failed to create bucket: %s\n", error.message); }
上传文件
您可以使用以下函数将文件上传到GridFS存储桶
mongoc_gridfs_bucket_open_upload_stream()
:打开一个可以写入文件内容的上传流mongoc_gridfs_bucket_upload_from_stream()
:将现有流的 内容上传到GridFS文件
向上传流写入
使用mongoc_gridfs_bucket_open_upload_stream()
函数为给定文件名创建一个上传流。该函数允许您在选项文档中指定配置信息,您可以将它作为参数传递。
以下示例使用上传流执行以下操作
为名为
"my_file"
的新GridFS文件打开一个可写流调用
mongoc_stream_write()
函数将数据写入由流指向的"my_file"
调用
mongoc_stream_close()
和mongoc_stream_destroy()
函数关闭并销毁指向"my_file"
的流
bson_error_t error; mongoc_stream_t *upload_stream = mongoc_gridfs_bucket_open_upload_stream (bucket, "my_file", NULL, NULL, &error); if (upload_stream == NULL) { fprintf (stderr, "Failed to create upload stream: %s\n", error.message); } else { const char *data = "Data to store"; mongoc_stream_write (upload_stream, data, strlen(data), -1); } mongoc_stream_close (upload_stream); mongoc_stream_destroy (upload_stream);
上传现有流
使用 mongoc_gridfs_bucket_upload_from_stream()
函数将流的 内容上传到新的 GridFS 文件。该 mongoc_gridfs_bucket_upload_from_stream()
函数允许您在选项文档中指定配置信息,并将其作为参数传递。
以下示例执行以下操作
调用
mongoc_stream_file_new_for_path()
函数以只读模式(O_RDONLY
)打开位于/path/to/input_file
的文件作为流调用
mongoc_gridfs_bucket_upload_from_stream()
函数将流的内容上传到名为"new_file"
的 GridFS 文件调用
mongoc_stream_close()
和mongoc_stream_destroy()
函数关闭和销毁流
mongoc_stream_t *file_stream = mongoc_stream_file_new_for_path ("/path/to/input_file", O_RDONLY, 0); bson_error_t error; if (!mongoc_gridfs_bucket_upload_from_stream (bucket, "new_file", file_stream, NULL, NULL, &error)) { fprintf (stderr, "Failed to upload file: %s\n", error.message); } mongoc_stream_close (file_stream); mongoc_stream_destroy (file_stream);
检索文件信息
在本节中,您可以了解如何检索存储在 GridFS 存储桶的 files
集合中的文件元数据。文件的元数据包含有关它引用的文件的信息,包括
文件的
_id
文件名
文件长度/大小
上传日期和时间
一个
metadata
文档,您可以在此存储任何其他信息
要检索 GridFS 存储桶中的文件,请调用 mongoc_gridfs_bucket_find()
函数并将存储桶作为参数传递。该函数返回一个游标,您可以通过该游标访问结果。
提示
有关 C 驱动程序中游标的更多信息,请参阅从游标访问数据 指南。
示例
以下代码示例展示了如何从GridFS存储桶中的文件检索并打印文件元数据。它使用一个while
循环遍历返回的光标并显示上传文件示例中的文件内容
mongoc_cursor_t *cursor = mongoc_gridfs_bucket_find(bucket, bson_new(), NULL); const bson_t *file_doc; while (mongoc_cursor_next(cursor, &file_doc)) { char *json = bson_as_json(file_doc, NULL); printf("%s\n", json); bson_free(json); } mongoc_cursor_destroy (cursor);
{ "_id" : { "$oid" : "..." }, "length" : 13, "chunkSize" : 261120, "uploadDate" : { "$date" : ... }, "filename" : "my_file", "metadata" : { } } { "_id" : { "$oid" : "..." }, "length" : 13, "chunkSize" : 261120, "uploadDate" : { "$date" : ... }, "filename" : "new_file", "metadata" : { } }
mongoc_gridfs_bucket_find()
函数接受各种查询规范。您可以使用其选项参数指定排序顺序、返回的最大文档数以及在返回之前跳过的文档数。要查看可用选项的列表,请参阅mongoc_collection_find_with_opts() API 文档。
下载文件
您可以使用以下函数从GridFS存储桶下载文件
mongoc_gridfs_bucket_open_download_stream()
:打开一个新的下载流,从中可以读取文件内容mongoc_gridfs_bucket_download_to_stream()
:将整个文件写入现有的下载流
从下载流中读取
您可以使用 mongoc_gridfs_bucket_open_download_stream()
函数创建下载流来从您的 MongoDB 数据库中下载文件。
此示例使用下载流执行以下操作
调用
mongoc_gridfs_bucket_open_download_stream()
函数来选择具有指定_id
值的 GridFS 文件并将其作为可读流打开调用
mongoc_stream_read()
函数来读取文件内容调用
mongoc_stream_close()
和mongoc_stream_destroy()
函数来关闭和销毁指向文件的下载流
char buf[512]; bson_value_t file_id; file_id.value_type = BSON_TYPE_OID; bson_oid_init_from_string (&file_id.value.v_oid, "66fb1b8ea0f84a74ee099e71"); bson_error_t error; mongoc_stream_t *download_stream = mongoc_gridfs_bucket_open_download_stream (bucket, &file_id, &error); if (!download_stream) { fprintf (stderr, "Failed to create download stream: %s\n", error.message); } mongoc_stream_read (download_stream, buf, 1, 1, 0); mongoc_stream_close (download_stream); mongoc_stream_destroy (download_stream);
注意
如果有多个具有相同文件名的文档,GridFS 将根据 uploadDate
字段确定的最新文件(给定名称)进行流式传输。
下载到现有流
您可以通过调用 mongoc_gridfs_bucket_download_to_stream()
函数将 GridFS 文件的内容下载到现有流中。
以下示例执行以下操作
调用
mongoc_stream_file_new_for_path()
函数以读写(O_RDWR
)模式打开位于/path/to/output_file
的文件作为流将具有指定
_id
值的 GridFS 文件下载到流中调用
mongoc_stream_close()
和mongoc_stream_destroy()
函数来关闭和销毁文件流
mongoc_stream_t *file_stream = mongoc_stream_file_new_for_path ("/path/to/output_file", O_RDWR, 0); bson_error_t error; if (!file_stream) { fprintf (stderr, "Error opening file stream: %s\n", error.message); } bson_value_t file_id; file_id.value_type = BSON_TYPE_OID; bson_oid_init_from_string (&file_id.value.v_oid, "66fb1b8ea0f84a74ee099e71"); if (!mongoc_gridfs_bucket_download_to_stream (bucket, &file_id, file_stream, &error)) { fprintf (stderr, "Failed to download file: %s\n", error.message); } mongoc_stream_close (file_stream); mongoc_stream_destroy (file_stream);
删除文件
使用 mongoc_gridfs_bucket_delete_by_id()
函数从您的bucket中删除文件的集合文档和相关块。这实际上会删除文件。
以下示例显示了如何通过引用其 _id
字段来删除文件
bson_error_t error; bson_oid_t oid; bson_oid_init_from_string (&oid, "66fb1b365fd1cc348b031b01"); if (!mongoc_gridfs_bucket_delete_by_id (bucket, &oid, &error)) { fprintf (stderr, "Failed to delete file: %s\n", error.message); }
注意
文件版本
mongoc_gridfs_bucket_delete_by_id()
函数一次只能删除一个文件。如果您想删除每个版本或具有相同文件名但上传时间不同的文件,请收集每个版本的 _id
值。然后,将每个 _id
值分别传递给 mongoc_gridfs_bucket_delete_by_id()
函数的单独调用。
API 文档
有关使用C驱动程序存储和检索大文件的更多信息,请参阅以下API文档