存储大文件
在此页面上
Overview
在本指南中,您可以学习;了解如何使用GridFS在MongoDB中存储和检索大文件。 GridFS是由MongoDB PHP库实现的规范,描述了如何在存储文件时将文件分割为数据段,并在检索文件时重新组合文件。 该库的GridFS实施是一个抽象,用于管理文件存储的操作和组织。
如果文件大小超过16 MB 的BSON文档大小限制,请使用GridFS 。 有关GridFS是否适合您的使用案例的更多详细信息,请参阅MongoDB Server手册中的 GridFS 。
GridFS 的工作原理
GridFS 在存储桶中组织文件,存储桶是一组包含文件数据段及其描述信息的MongoDB 集合。存储桶包含以下集合,使用 GridFS 规范中定义的约定命名:
chunks
集合存储二进制文件数据段。files
集合存储文件元数据。
当您创建新的GridFS存储桶时,该库会创建上述集合,并以默认存储桶名称fs
作为前缀,除非您指定其他名称。 该库还会对每个集合创建索引,以确保高效检索文件和相关元数据。 如果GridFS存储桶不存在,则该库仅在执行第一次写入操作时才会创建该存储桶。 仅当索引不存在且存储桶为空时,库才会创建索引。 有关GridFS索引的更多信息,请参阅MongoDB Server手册中的GridFS索引。
使用GridFS存储文件时,该库会将文件分割成较小的数据段,每个数据段由chunks
集合中的单独文档表示。 它还在files
集合中创建一个文档,其中包含文件ID、文件名和其他文件元数据。 您可以通过将流MongoDB PHP库以使用或创建新流并直接写入来上传文件。 要学习;了解有关流的详情,请参阅 流 在PHP手册中。
查看下图,了解GridFS在将文件上传到存储桶时如何拆分文件:
检索文件时, GridFS从指定存储桶的files
集合中获取元数据,并使用该信息从chunks
集合中的文档重建文件。 您可以通过将文件内容写入现有流或创建指向该文件的新流来读取该文件。
创建 GridFS 存储桶
要从GridFS存储或检索文件,请对数据库调用MongoDB\Database::selectGridFSBucket()
方法。 此方法访问现有存储桶,如果不存在,则创建新存储桶。
以下示例对db
数据库调用selectGridFSBucket()
方法:
$bucket = $client->db->selectGridFSBucket();
自定义存储桶
您可以通过将指定选项值的大量传递给selectGridFSBucket()
方法来自定义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 261120 .Type: integer |
readConcern | Specifies the read concern to use for bucket operations. The default value is the
database's read concern. Type: MongoDB\Driver\ReadConcern |
readPreference | Specifies the read preference to use for bucket operations. The default value is the
database's read preference. Type: MongoDB\Driver\ReadPreference |
writeConcern | Specifies the write concern to use for bucket operations. The default value is the
database's write concern. Type: MongoDB\Driver\WriteConcern |
以下示例通过将大量传递给设置bucketName
选项的selectGridFSBucket()
来创建名为'myCustomBucket'
的存储桶:
$custom_bucket = $client->db->selectGridFSBucket( ['bucketName' => 'myCustomBucket'] );
上传文件
您可以使用以下方法将文件上传到GridFS存储桶:
MongoDB\GridFS\Bucket::openUploadStream()
:打开新的上传流,您可以在其中写入文件内容MongoDB\GridFS\Bucket::uploadFromStream()
:将现有流的内容上传到GridFS文件
写入上传流
使用openUploadStream()
方法为给定文件名创建上传流。 openUploadStream()
方法允许您在选项大量中指定配置信息,您可以将其作为参数传递。
此示例使用上传流来执行以下操作:
为名为以下内容的新GridFS文件打开可写流:
'my_file'
将大量参数中的
metadata
选项设置为openUploadStream()
方法调用
fwrite()
方法以写入'my_file'
,流指向调用
fclose()
方法关闭指向'my_file'
的流
$stream = $bucket->openUploadStream('my_file', [ 'metadata' => ['contentType' => 'text/plain'] ]); fwrite($stream, 'Data to store'); fclose($stream);
上传现有流
使用uploadFromStream()
方法将流的内容上传到新的GridFS文件。 uploadFromStream()
方法允许您在选项大量中指定配置信息,您可以将其作为参数传递。
此示例将执行以下动作:
调用
fopen()
方法以在二进制读取 (rb
)模式将位于/path/to/input_file
的文件作为流打开调用
uploadFromStream()
方法将流的内容上传到名为'new_file'
的GridFS文件
$file = fopen('/path/to/input_file', 'rb'); $bucket->uploadFromStream('new_file', $file);
检索文件信息
在本部分中,您可以了解如何检索存储在 GridFS 存储桶的 files
集合的文件元数据。元数据包含所引用文件的相关信息,包括:
文件的
_id
文件的名称
文件的长度/大小
上传日期和时间
您可以在其中存储任何其他信息的
metadata
文档
要从GridFS存储桶检索文件,请对MongoDB\GridFS\Bucket
实例调用MongoDB\GridFS\Bucket::find()
方法。 该方法返回一个MongoDB\Driver\Cursor
实例,您可以从该实例访问权限结果。 要学习;了解有关MongoDB PHP库中Cursor
对象的更多信息,请参阅从游标访问数据指南。
例子
以下代码示例向您展示如何从GridFS存储桶中的文件检索和打印文件元数据。 它使用foreach
循环遍历返回的游标,并显示上传文件示例中上传的文件的内容:
$files = $bucket->find(); foreach ($files as $file_doc) { echo toJSON($file_doc), PHP_EOL; }
{ "_id" : { "$oid" : "..." }, "chunkSize" : 261120, "filename" : "my_file", "length" : 13, "uploadDate" : { ... }, "metadata" : { "contentType" : "text/plain" }, "md5" : "6b24249b03ea3dd176c5a04f037a658c" } { "_id" : { "$oid" : "..." }, "chunkSize" : 261120, "filename" : "new_file", "length" : 13, "uploadDate" : { ... }, "md5" : "6b24249b03ea3dd176c5a04f037a658c" }
find()
方法接受各种查询规范。 您可以使用其$options
参数指定排序顺序、要返回的最大文档数以及在返回之前要跳过的文档数。 要查看可用选项列表,请参阅API文档。
注意
前面的示例调用toJSON()
方法将文件元数据打印为扩展JSON,在以下代码中定义:
function toJSON(object $document): string { return MongoDB\BSON\Document::fromPHP($document)->toRelaxedExtendedJSON(); }
下载文件
您可以使用以下方法从GridFS存储桶下载文件:
MongoDB\GridFS\Bucket::openDownloadStreamByName()
或MongoDB\GridFS\Bucket::openDownloadStream()
:打开新的下载流,您可以从中读取文件内容MongoDB\GridFS\Bucket::downloadToStream()
:将整个文件写入现有下载流
从下载流中读取
您可以使用MongoDB\GridFS\Bucket::openDownloadStreamByName()
方法创建下载流,从MongoDB 数据库下载文件。
此示例使用下载流来执行以下操作:
选择在写入上传流示例中上传的名为
'my_file'
的GridFS文件,并将其作为可读流打开调用
stream_get_contents()
方法以读取'my_file'
的内容打印文件内容
调用
fclose()
方法关闭指向'my_file'
的下载流
$stream = $bucket->openDownloadStreamByName('my_file'); $contents = stream_get_contents($stream); echo $contents, PHP_EOL; fclose($stream);
"Data to store"
注意
如果存在多个具有相同文件名的文档, GridFS将流具有给定名称(由uploadDate
字段确定)的最新文件。
或者可以使用 MongoDB\GridFS\Bucket::openDownloadStream()
方法将文件的 _id
字段作为参数:
$stream = $bucket->openDownloadStream(new ObjectId('66e0a5487c880f844c0a32b1')); $contents = stream_get_contents($stream); fclose($stream);
注意
GridFS流媒体API无法加载部分数据段。 当下载流需要从数据块拉取一个MongoDB时,它会将整个数据块入内存。 255千字节的默认数据数据块大小通常已足够,但您可以减小数据数据块大小以减少内存开销,或在处理较大文件时增加数据数据块大小。 有关设置数据数据块大小的更多信息,请参阅本页的自定义存储桶部分。
下载文件修订版本
当您的存储桶包含多个股票相同文件名的文件时, GridFS默认文件最近上传的版本。 为了区分同名的每个文件, GridFS为它们分配一个修订版本号,按上传时间排序。
原始文件修订号是0
,下一个最新的文件修订号是1
。 您还可以指定与修订的新近度相对应的负值。 修订值-1
引用最新修订版本, -2
引用下一个最新修订版本。
您可以通过将选项大量传递给openDownloadStreamByName()
方法并指定revision
选项来指示GridFS下载特定的文件修订版。 以下示例读取名为'my_file'
的原始文件的内容,而不是最新修订的内容:
$stream = $bucket->openDownloadStreamByName('my_file', ['revision' => 0]); $contents = stream_get_contents($stream); fclose($stream);
下载到现有流
您可以通过在存储桶上调用MongoDB\GridFS\Bucket::downloadToStream()
方法,将GridFS文件的内容下载到现有流。
此示例将执行以下动作:
调用
fopen()
方法以在二进制写入(wb
)模式将位于/path/to/output_file
的文件作为流打开将
_id
值为ObjectId('66e0a5487c880f844c0a32b1')
的GridFS文件下载量到流
$file = fopen('/path/to/output_file', 'wb'); $bucket->downloadToStream( new ObjectId('66e0a5487c880f844c0a32b1'), $file, );
重命名文件
使用 MongoDB\GridFS\Bucket::rename()
方法更新存储桶中 GridFS 文件的名称。您必须用文件的 _id
字段而不是文件名来指定要重命名的文件。
以下示例展示了如何通过引用文档的_id
字段将filename
字段更新为'new_file_name'
:
$bucket->rename(new ObjectId('66e0a5487c880f844c0a32b1'), 'new_file_name');
注意
文件修订
rename()
方法一次仅支持更新一个文件的名称。 如果要重命名每个文件修订版或上传时间不同但股票相同文件名的文件,请收集每个修订版的_id
值。 然后,将每个值分别传递给rename()
方法。
删除文件
使用MongoDB\GridFS\Bucket::delete()
方法从存储桶中删除文件的集合文档和关联的数据段。 这实际上删除了该文件。 您必须用文件的_id
字段而不是文件名来指定文件。
下面的示例展示了如何通过引用文件的 _id
字段来删除文件:
$bucket->delete(new ObjectId('66e0a5487c880f844c0a32b1'));
注意
文件修订
delete()
方法一次仅支持删除一个文件。 如果要删除每个文件修订版本,或上传时间不同但股票相同文件名的文件,请收集每个修订版本的_id
值。 然后,将每个值分别传递给delete()
方法。
API 文档
要学习;了解有关使用MongoDB PHP库存储和检索大文件的更多信息,请参阅以下API文档: