GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。
GridFS 也是文件存储的一种方式,但是它是存储在MonoDB的集合中。
GridFS 会将大文件对象分割成多个小的chunk
,每个chunk
将作为MongoDB的一个文档(document)被存储在chunks
集合中。
GridFS 将文件存储在两个集合中:
-
chunks
存储二进制块。有关详细信息,请参阅块集合
-
files
存储文件的元数据。有关详细信息,请参阅文件集合
GridFS 通过将集合的存储桶名称作为前缀,将集合放在公共存储桶中。默认情况下,GridFS 使用两个集合,其存储桶名为 :fs
fs.files
{
"_id" : <ObjectId>,
"length" : <num>,
"chunkSize" : <num>,
"uploadDate" : <timestamp>,
"md5" : <hash>,
"filename" : <string>,
"contentType" : <string>,
"aliases" : <string array>,
"metadata" : <any>,
}
fs.chunks
{
"_id" : <ObjectId>,
"files_id" : <ObjectId>,
"n" : <num>,
"data" : <binary>
}
GridFS使用
使用shell命令
MongoDB 提供
mingofiles
工具,可以使用命令行来操作GridFS。四个主要命令,分别为:
put
存储命令
get
获取命令
list
列表命令
delete
删除命令
# 存储文件 (执行后会在数据库中就会多出2个集合,它们存储了GridFS文件系统的所有文件信息)
- mongofiles -d 数据库名字 -l "要上传的文件的完整路径名" put "上传后的文件名"
# 获取文件 (如果不写-l以及后面的路径参数,则保存到当前位置。)
- mongofiles -d 数据库名字 -l "将文件保存在本地的完整路径名" get "GridFS文件系统中的文件名"
#列表文件
- mongofiles -d 数据库名字 list
#删除文件
- mongofiles -d 数据库名字 delete " 文件名 "
使用API
MongoDB支持多种编程语言驱动。比如c、java、C#、NodeJS等。因此可以使用这些语言MongoDB驱动API操作,扩展GridFS。
以SpringBoot
为例:
在 上次Mongo测试基础上
官方文档教程
上传文件
//文件操作
@Autowired
GridFsTemplate gridFsTemplate;
@Test
public void testUpload() throws FileNotFoundException {
File file = new File("D:\\Test\\demo.zip");
// 获取文件名
String fileName=file.getName().substring(0,file.getName().lastIndexOf("."));
// 获取文件后缀
String contentType = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length());
// 获取文件流
FileInputStream fileInputStream = new FileInputStream(file);
// 上传 return "_id"
ObjectId objectId = gridFsTemplate.store(fileInputStream, file.getName(),contentType);
System.out.println(objectId);
}
自定义桶名称
在 config
包下创建 MongoConfig
类
@Configuration
public class MongoConfig {
@Bean
public GridFsTemplate gridFsTemplate(MongoDatabaseFactory dbFactory, MongoConverter converter) {
return new GridFsTemplate(dbFactory, converter, "pictureFs");
}
}
再在测试类中上传文件
,就上传到了pictureFs
桶中
上传文件 -法2
使用GridFSBucket.uploadFromStream 方法
可以使用 GridFSUploadOptions 来配置块大小或包含其他元数据。
@Test void testUpload2(){
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"fs");
try {
File file = new File("D:\\Test\\test.zip");
// 获取文件名
String fileName=file.getName().substring(0,file.getName().lastIndexOf("."));
// 获取文件后缀
String contentType = file.getName().substring(file.getName().lastIndexOf(".") + 1);
// 获取文件流
InputStream streamToUploadFrom = new FileInputStream(file);
// 配置块大小 或 包含其他元数据
GridFSUploadOptions options = new GridFSUploadOptions()
.chunkSizeBytes(358400)
.metadata(new Document("type", contentType));
ObjectId fileId = bucket.uploadFromStream(fileName, streamToUploadFrom, options);
System.out.println("文件上传成功-"+fileId);
} catch (FileNotFoundException e){
System.out.println("FileNotFoundException:" + e.getMessage());
}
}
查询文件
//文件查询
@Test
public void testFind(){
// findAll
// 可以为 GridFSBuckets.create() 方法指定存储桶名称
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"bucketName");
bucket.find().forEach(e-> System.out.println(e.getFilename()));
}
提供设置过滤器来限制返回的结果
bucket.find(Filters.eq("filename","测试文件")).forEach(e-> System.out.println(e.getFilename()));
下载文件
@Test
public void testDownload() throws IOException{
ObjectId fileId= new ObjectId("626d45071aa7187f36380ee9");
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"fs");
try {
// 使用输出流 设置要保存的路径
FileOutputStream streamToDownloadTo = new FileOutputStream("D:\\Test\\downTest.zip");
// 通过Id下载文件
bucket.downloadToStream(fileId, streamToDownloadTo);
// 关闭输出流
streamToDownloadTo.close();
System.out.println(streamToDownloadTo);
} catch (IOException e) {
System.out.println("IOException:" + e.getMessage());
}
}
重命名文件
@Test
public void testRename(){
ObjectId fileId= new ObjectId("626d45071aa7187f36380ee9");
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"fs");
bucket.rename(fileId,"Test");
}
删除文件
public void deleteRename(){
ObjectId fileId= new ObjectId("626ba621ac6c406b9208cfb6");
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"fs");
bucket.delete(fileId);
}
以上,就学习了 GridFS在 SpringBoot 中的基本使用方法
扩充
multer-gridfs-storage
:Mul GridFS存储引擎,用于Multer将上传的文件直接存储到MongoDbGitHub - devconcept/multer-gridfs-storage
gridfs-stream
:轻松将文件流式传输到MongoDB GridFS和从MongoDB GridFS流式传输文件。GitHub - aheckmann/gridfs-stream
GridFS也有一些问题,
比如它读取文件的性能并不是很好,因为我们需要查询两次集合(先是fs.files,再是fs.chunks)才能将文件拼凑出来。
如果我们的文件需要经常修改,那么GridFS也不合适,因为GridFS没法修改单独的某个分块,要修改文件的话,需要先将该文件删除,然后重新上传。