文档菜单
文档首页
/ / /
C 驱动程序
/

存储大文件

在本页

  • 概述
  • GridFS 的工作原理
  • 创建 GridFS 存储桶
  • 自定义存储桶
  • 上传文件
  • 写入上传流
  • 上传现有流
  • 检索文件信息
  • 示例
  • 下载文件
  • 从下载流中读取
  • 下载到现有流
  • 删除文件
  • API 文档

在本指南中,您可以学习如何使用 GridFS 在 MongoDB 中存储和检索大文件。GridFS 是由 C 驱动程序实现的一个规范,它描述了在存储时如何将文件分割成块,以及在检索时如何重新组装它们。驱动程序对 GridFS 的实现是一个抽象,它管理文件存储的操作和组织。

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

GridFS 以 的形式组织文件,桶是一组包含文件块及其描述信息的 MongoDB 集合。该桶包含以下集合,使用 GridFS 规范中定义的约定命名

  • chunks 集合存储二进制文件块。

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

当您执行第一个写入操作时,如果 GridFS 桶不存在,驱动程序将创建该桶。桶包含前面提到的集合,并以默认桶名称 fs 前缀,除非您指定了不同的名称。为了确保高效检索文件及其相关元数据,如果这些集合不存在且桶为空,驱动程序还会在每个集合上创建索引。

有关 GridFS 索引的更多信息,请参阅 MongoDB 服务器手册中的 GridFS 索引

当使用GridFS存储文件时,驱动程序会将文件分割成更小的块,每个块由chunks集合中的一个单独的文档表示。它还在files集合中创建一个文档,该文档包含文件ID、文件名和其他文件元数据。您可以通过传递一个流到C驱动程序以消耗它或创建一个新流并直接写入它来上传文件。

以下图显示了当文件上传到存储桶时GridFS如何分割文件

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

当您从GridFS检索文件时,它会从指定存储桶的files集合中获取元数据,并使用这些信息从chunks集合中的文档重新构建文件。您可以通过将文件内容写入现有流或创建一个指向文件的流来读取文件。

要使用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() 函数的单独调用。

有关使用C驱动程序存储和检索大文件的更多信息,请参阅以下API文档

返回

事务