存储大文件
Overview
在本指南中,您可以学习;了解如何使用GridFS在MongoDB中存储和检索大文件。 GridFS是由C驾驶员实现的规范,描述了如何在存储文件时将文件分割为数据段,并在检索文件时重新组合文件。 GridFS驱动程序的实施是一个抽象,用于管理文件存储的操作和组织。
如果文件大小超过16 MB 的BSON文档大小限制,请使用GridFS 。 有关GridFS是否适合您的使用案例的更多详细信息,请参阅MongoDB Server手册中的 GridFS 。
GridFS 的工作原理
GridFS 在存储桶中组织文件,存储桶是一组包含文件数据段及其描述信息的MongoDB 集合。存储桶包含以下集合,使用 GridFS 规范中定义的约定命名:
chunks
集合存储二进制文件数据段。files
集合存储文件元数据。
当您执行第一次写入操作时,驾驶员会创建GridFS存储桶(如果不存在)。存储桶包含以默认存储桶名称 fs
为前缀的前面的集合,除非您指定了其他名称。为了确保有效检索文件和相关元数据,驾驶员还会在每个集合上创建索引(如果它们不存在)以及存储桶为空。
有关GridFS索引的更多信息,请参阅MongoDB Server手册中的GridFS索引。MongoDB Server
使用GridFS存储文件时,驾驶员会将文件分割成较小的数据段,每个数据段由 chunks
集合中的单独文档表示。它还在 files
集合中创建一个文档,其中包含文件ID、文件名和其他文件元数据。您可以通过将流C驾驶员以使用或创建新流并直接写入来上传文件。
下图展示了GridFS在上传到存储桶时如何分割文件:
当您从GridFS检索文件时,它会从指定存储桶中的 files
集合中获取元数据,并使用该信息根据 chunks
集合中的文档重建文件。您可以通过将文件内容写入现有流或创建指向该文件的新流来读取该文件。
创建 GridFS 存储桶
要使用GridFS,请先调用 mongoc_gridfs_bucket_new()
函数。此函数创建新的 mongoc_gridfs_bucket_t
结构或访问现有的 mongoc_gridfs_bucket_t
并接受以下参数:
Database :指定要在其中创建存储桶的数据库
选项文档:指定用于自定义存储桶的选项,或
NULL
读取偏好 :指定用于读取操作的读取偏好(read preference),或
NULL
以继承数据库的读取偏好(read preference)错误位置:指定错误值的位置,或
NULL
以下示例调用 mongoc_gridfs_bucket_new()
函数并将 db
数据库作为参数传递:
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 | Specifies the bucket name to use as a prefix for the files and chunks collections.
The default value is "fs" .Type: string |
chunkSizeBytes | Specifies the chunk size that GridFS splits files into. The default value is 255 kB. Type: int32 |
readConcern | Specifies the read concern to use for bucket operations. The default value is the
database's read concern. Type: mongoc_read_concern_t |
writeConcern | Specifies the write concern to use for bucket operations. The default value is the
database's write concern. Type: mongoc_write_concern_t |
以下示例通过将选项文档传递给设置 bucketName
选项的 mongoc_gridfs_bucket_new()
来创建名为 "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()
函数为给定文件名创建上传流。 mongoc_gridfs_bucket_open_upload_stream()
函数允许您在选项文档中指定配置信息,您可以将其作为参数传递。
此示例使用上传流来执行以下操作:
为名为以下内容的新GridFS文件打开可写流:
"my_file"
调用
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()
函数并将您的存储桶作为参数传递。该函数返回一个游标,您可以通过该游标访问权限结果。
例子
以下代码示例向您展示如何从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()
函数从存储桶中删除文件的集合文档和关联的数据段。这实际上删除了该文件。
下面的示例展示了如何通过引用文件的 _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文档: