MongoDB GridFS(命令行+php操作)
一、GridFS是什么 & 为什么需要它
我们知道目前MongoDB的BSON文件最大只能是16M,也就是说单个文档最多只能存储16M的数据,那么如果需要MongoDB存储超过16M的大文件该怎么办呢?这就需要通过MongoDB的GridFS规范来实现了。
GridFS并不是MongoDB自身的特性,只是一种将大型文件存储在MongoDB的文件规范,借助GridFS,我们可以很好地管理存储在MongoDB中的大文件。由于GridFS只是标准MongoDB框架下存储文件的一种不同的方式而已,所以也是受BSON最大文件大小限制的,单个文档最大不能超过16M。GridFS使用两个集合来存储文件:fs.files和fs.chunks,fs.files用于存储文件名称和大小等元数据,fs.chunks则用于存储文件内容,fs.chunks中每个文档最大为256K,大文件内容被分割成多个块存储于多个fs.chunks文档中,每个fs.chunks文档都存储了文件id(files中的_id键值)和序号(属于文件内容的第几个块)。查看文件时,先查出文件在fs.files中的文档,再根据其ID在fs.chunks中查询存储该文件内容的文档,根据其序号先后顺序进行拼凑,即可读取整个文件的内容了。
二、命令行操作GridFS
可以使用MongoDB安装目录下的bin子目录中的mongofiles命令行工具来直接操作GridFS。
1. 存储文件:
mongofiles存储文件使用put命令。这里我使用MongoDB的一本电子书作为例子,文件大小为56.9M。
注意:GridFS可以添加相同文件名的文件,而且就算两个文件完全相同,得到的md5值一样,GridFS还是会当成新的文件进行存储,而不会更新原有文件。
2. 查询文件列表:
mongofiles查询文件列表使用list命令。
使用mongo命令行工具查询该文件在MongoDB中的存储内容(数据库为test):
(上图中fs.chunks文档只是截取了前几个而已,图中注明了fs.files和fs.chunks集合中文档的字段含义,其中fs.hunks还有一个data字段是用于存储文件二进制数据的,这里为了避免输出一大堆的二进制数据,没有把这个字段查出来。)
3. 搜索文件:
mongofiles查询文件列表使用search命令(模糊搜索)。
4. 删除文件:
mongofiles查询文件列表使用delete命令(需要输入确切文件名)。
这时再使用mongofile list命令查询发现已经没有这个文件了,集合fs.files和fs.chunks也都已经没有存储该文件的任何文档了。
注意:delete命令是基于文件名删除文件的,将会删除所有同名的文件。
5. 读取文件:
mongofiles使用get命令读取文件内容,把MongoDB中存储的某个文件的内容读取出来,写入一个文件中。
(这个命令会把MongoDB中存储的名为“d:\mongodb\files\MongoDB.pdf”的文件内容读取出来输出到文件d:\mongodb\files\MongoDB.pdf中,若文件已存在则会被覆写。)
三、php操作GridFS
MongoDB的PHP驱动也支持使用GridFS进行大文件存储。
1. 存储文件:
这里以存储一张图片为例:
1 2 3 4 5 6 | $mongo = new mongoClient( 'mongodb://localhost:27017' );//连接MongoDB(ip:port) $db = $mongo ->cdn; //选择一个数据库来存储文件,这里选择数据库cdn $gridfs = $db ->getGridFS(); //获取MongoGridFS对象 $ret = $gridfs ->storeFile( '/data/wwwroot/cdn/myPhoto.jpg' ); //存储文件 echo '<pre>' ; print_r( $ret ); |
若文件存储成功,将返回一个MongoId对象,打印出来是这样的:
这个MongoId对象就是文件存储在fs.files集合中的文档的_id键的值,我们可以把’$id’键对应的这个字符串记录起来,以便以后可以根据这个字符串读取这个文件。注意不能根据文件名来读取文件,因为可能存在多个同名文件,只有这个_id键才是唯一的。
除了storeFile()方法,你也可以使用storeBytes()方法存储文件的二进制流:
1 2 | $data = file_get_contents ( '/data/wwwroot/cdn/ycl.png' ); $ret = $gridfs ->storeBytes( $data , array ( 'desc' => '这是ycl的照片,哈哈!' , 'info' => '无可奉告' )); //可以利用第二个参数添加一些额外信息 |
若文件是用户上传的,还可以使用storeUpload()方法直接存储用户上传的文件,该函数的参数就是html页面中上传文件的表单字段名称:
1 2 3 | $ret = $gridfs ->storeUpload( 'photo' ); 或: $ret = $gridfs ->storeFile( $_FILES [ 'photo' ][ 'tmp_name' ]); |
2. 文件的查询和读取:
首先我们查询一下刚刚存储的这张图片在fs.files集合中是怎么存储的,这里就利用刚才返回的MongoId对象进行查看:
1 2 3 4 5 6 | $mongo = new mongoClient( '192.168.97.200:27020' ); $db = $mongo ->cdn; $collection = $db ->selectCollection( 'fs.files' ); $doc = $collection ->findOne([ '_id' => new MongoId( '5a73e86f2ff2de2207a4bd2d' )]); echo '<pre>' ; print_r( $doc ); |
打印出来是这样的:
(若是利用storeBytes()方法进行存储并且添加了额外信息的,’filename’字段将不复存在,被添加的额外信息字段取代)
下面直接读取这个文件,在浏览器上输出来看看:
1 2 3 4 5 6 | $mongo = new mongoClient( 'mongodb://localhost:27017' ); $db = $mongo ->cdn; //选择存储文件的数据库 $gridfs = $db ->getGridFS(); $doc = $gridfs ->findOne([ '_id' => new MongoId( '5a73e86f2ff2de2207a4bd2d' )]); header( 'Content-type: image/jpg' ); //输出图片头 echo $doc ->getBytes(); //输出数据流 |
以上代码运行即可在浏览器上看到存储的图片了。
所以,使用php操作GridFS存储和读取大文件就是这么简单,你只需要调用MongoGridFS类提供的存储文件的方法进行存储,然后将返回的MongoId对象的字符串记录下来,作为读取文件方法的参数进行文件读取就可以了。你甚至完全不必关心文件在fs.files和fs.chunks两个集合中是怎么存储的,读取文件的时候又需要怎么关联查询,这些统统不用你操心!
当然,如果你不嫌麻烦,完全可以自己查询fs.chunks集合进行文件读取:
1 2 3 4 5 6 7 8 | $mongo = new mongoClient( 'mongodb://localhost:27017' ); $db = $mongo ->cdn; $collection = $db ->selectCollection( 'fs.chunks' ); $cursor = $collection ->find([ 'files_id' => new MongoId( '5a74206f2ff2de1c07a4bd2d' )])->sort([ 'n' => 1]); header( 'Content-type: application/pdf' ); while ( $chunk = $cursor ->getNext()) { //逐个chunk输出,避免内存超出 echo $chunk [ 'data' ]->bin; } |
这种读取方式虽然麻烦了些,但是性能上比使用MongoGridFS类进行查询要好一些,我自己进行了一下测试,读取并在浏览器显示一个56.9M的pdf文档,使用MongoGridFS类读取花费8秒多,而使用下面这种方法只要6秒多,节省了2秒钟的时间!
3. 删除文件:
删除MongoDB中存储的文件使用delete()方法:
1 2 3 4 5 6 | $mongo = new mongoClient( 'mongodb://localhost:27017' ); $db = $mongo ->cdn; $gridfs = $db ->getGridFS(); $ret = $gridfs -> delete ( new MongoId( '5a73e86f2ff2de2207a4bd2d' )); echo '<pre>' ; print_r( $ret ); |
当然,还有remove()方法也可以进行文件的删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)