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

存储大文件

本页内容

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

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

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

GridFS将文件组织在一个名为“存储桶”的结构中,它是一组包含文件块及其描述信息的MongoDB集合。存储桶包含以下集合,这些集合的命名遵循GridFS规范中定义的约定

  • chunks 集合,用于存储二进制文件块

  • files 集合,用于存储文件元数据

当您首次向其中写入数据时,如果GridFS存储桶不存在,则驱动程序会创建它。存储桶包含以默认存储桶名称fs开头的先前集合,除非您指定了不同的名称。为了确保高效地检索文件和相关元数据,驱动程序会在每个集合上创建索引。驱动程序确保在执行GridFS存储桶的读写操作之前,这些索引存在。

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

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

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

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

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

要开始将文件存储或从GridFS检索文件,请调用数据库上的gridfs_bucket()方法。此方法访问现有的存储桶或创建一个新存储桶(如果不存在)。

以下示例在db数据库上调用gridfs_bucket()方法

auto bucket = db.gridfs_bucket();

您可以通过将mongocxx::options::gridfs::bucket类的实例作为可选参数传递给gridfs_bucket()方法来自定义GridFS存储桶配置。以下表格描述了您可以在mongocxx::options::gridfs::bucket实例中设置的字段

字段
描述

bucket_name

指定用于文件和块集合的前缀的存储桶名称。默认值是 "fs"
类型: std::string

chunk_size_bytes

指定GridFS将文件拆分成的块大小。默认值是 261120
类型: std::int32_t

read_concern

指定用于存储桶操作的读取关注度。默认值是数据库的读取关注度。
类型: mongocxx::read_concern

read_preference

指定用于存储桶操作的读取偏好。默认值是数据库的读取偏好。
类型: mongocxx::read_preference

write_concern

指定用于存储桶操作的写入关注度。默认值是数据库的写入关注度。
类型: mongocxx::write_concern

以下示例通过设置mongocxx::options::gridfs::bucket实例的bucket_name字段创建一个名为"myCustomBucket"的存储桶

mongocxx::options::gridfs::bucket opts;
opts.bucket_name("myCustomBucket");
auto bucket = db.gridfs_bucket(opts);

您可以使用以下方法将文件上传到GridFS存储桶

使用 open_upload_stream() 方法创建指定文件名的上传流。该 open_upload_stream() 方法允许你在 options::gridfs::upload 实例中指定配置信息,并将其作为参数传递。

以下示例使用上传流执行以下操作

  • 设置选项实例的 chunk_size_bytes 字段

  • 为名为 "my_file" 的新 GridFS 文件打开一个可写流并应用 chunk_size_bytes 选项

  • 调用 write() 方法将数据写入由流指向的 my_file

  • 调用 close() 方法关闭指向 my_file 的流

mongocxx::options::gridfs::upload opts;
opts.chunk_size_bytes(1048576);
auto uploader = bucket.open_upload_stream("my_file", opts);
// ASCII for "HelloWorld"
std::uint8_t bytes[10] = {72, 101, 108, 108, 111, 87, 111, 114, 108, 100};
for (auto i = 0; i < 5; ++i) {
uploader.write(bytes, 10);
}
uploader.close();

使用 upload_from_stream() 方法将流的内容上传到新的 GridFS 文件。该 upload_from_stream() 方法允许你在 options::gridfs::upload 实例中指定配置信息,并将其作为参数传递。

以下示例执行以下操作

  • 以二进制读取模式打开位于 /path/to/input_file 的文件作为流

  • 调用 upload_from_stream() 方法将流的内容上传到名为 "new_file" 的 GridFS 文件

std::ifstream file("/path/to/input_file", std::ios::binary);
bucket.upload_from_stream("new_file", &file);

在本节中,您可以学习如何检索存储在 GridFS 桶的 files 集合中的文件元数据。元数据包含有关所引用文件的信息,包括

  • 文件的 _id

  • 文件名

  • 文件长度/大小

  • 上传日期和时间

  • 一个可以存储其他信息的 metadata 文档

要从 GridFS 桶检索文件,请调用您的桶上的 mongocxx::gridfs::bucket::find() 方法。该方法返回一个 mongocxx::cursor 实例,您可以从中访问结果。有关游标的更多信息,请参阅从游标访问数据指南。

以下代码示例演示了如何从GridFS存储桶中的文件检索并打印文件元数据。它使用一个for循环遍历返回的游标并显示在上传文件示例中上传的文件内容。

auto cursor = bucket.find({});
for (auto&& doc : cursor) {
std::cout << bsoncxx::to_json(doc) << std::endl;
}
{ "_id" : { "$oid" : "..." }, "length" : 13, "chunkSize" : 261120, "uploadDate" :
{ "$date" : ... }, "filename" : "new_file" }
{ "_id" : { "$oid" : "..." }, "length" : 50, "chunkSize" : 1048576, "uploadDate" :
{ "$date" : ... }, "filename" : "my_file" }

find()方法接受各种查询规范。您可以使用其mongocxx::options::find参数来指定排序顺序、返回的最大文档数以及返回前要跳过的文档数。要查看可用选项的列表,请参阅API文档。

您可以通过以下方法从GridFS存储桶下载文件

您可以使用open_download_stream()方法创建下载流来从MongoDB数据库下载文件。

此示例使用下载流执行以下操作

  • 检索名为"new_file"的GridFS文件的_id

  • _id值传递给open_download_stream()方法以将文件作为可读流打开

  • 创建一个buffer向量以存储文件内容

  • 调用read()方法将文件内容从downloader流读取到向量中

auto doc = db["fs.files"].find_one(make_document(kvp("filename", "new_file")));
auto id = doc->view()["_id"].get_value();
auto downloader = bucket.open_download_stream(id);
std::vector<uint8_t> buffer(downloader.file_length());
downloader.read(buffer.data(), buffer.size());

您可以通过在您的bucket上调用download_to_stream()方法将GridFS文件的内容下载到现有流中。

以下示例执行以下操作

  • 以二进制写入模式打开位于/path/to/output_file的文件

  • 检索名为"new_file"的GridFS文件的_id

  • _id值传递给download_to_stream()以将文件下载到流中

std::ofstream output_file("/path/to/output_file", std::ios::binary);
auto doc = db["fs.files"].find_one(make_document(kvp("filename", "new_file")));
auto id = doc->view()["_id"].get_value();
bucket.download_to_stream(id, &output_file);

使用delete_file()方法删除文件的集合文档和与bucket关联的块。这实际上会删除文件。您必须通过其_id字段指定文件,而不是其文件名。

以下示例展示了如何通过将文件的_id值传递给delete_file()来删除名为"my_file"的文件。

auto doc = db["fs.files"].find_one(make_document(kvp("filename", "my_file")));
auto id = doc->view()["_id"].get_value();
bucket.delete_file(id);

注意

文件版本

delete_file()方法一次只能删除一个文件。如果您想删除每个文件版本,或者具有相同文件名但上传时间不同的文件,请收集每个版本的_id值。然后,在每个单独的调用中将每个_id值传递给delete_file()方法。

要了解如何使用 C++ 驱动存储和检索大文件,请参阅以下 API 文档

返回

批量写入

© . All rights reserved.