GridFS 用于存儲(chǔ)和恢復(fù)那些超過16M(BSON文件限制)的文件(如:圖片、音頻、視頻等)。
GridFS 也是文件存儲(chǔ)的一種方式,但是它是存儲(chǔ)在MonoDB的集合中。
GridFS 會(huì)將大文件對(duì)象分割成多個(gè)小的chunk,每個(gè)chunk將作為MongoDB的一個(gè)文檔(document)被存儲(chǔ)在chunks集合中。
GridFS 將文件存儲(chǔ)在兩個(gè)集合中:
-
chunks存儲(chǔ)二進(jìn)制塊。有關(guān)詳細(xì)信息,請(qǐng)參閱塊集合 -
files存儲(chǔ)文件的元數(shù)據(jù)。有關(guān)詳細(xì)信息,請(qǐng)參閱文件集合
GridFS 通過將集合的存儲(chǔ)桶名稱作為前綴,將集合放在公共存儲(chǔ)桶中。默認(rèn)情況下,GridFS 使用兩個(gè)集合,其存儲(chǔ)桶名為 :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。四個(gè)主要命令,分別為:
put存儲(chǔ)命令
get獲取命令
list列表命令
delete刪除命令
# 存儲(chǔ)文件 (執(zhí)行后會(huì)在數(shù)據(jù)庫中就會(huì)多出2個(gè)集合,它們存儲(chǔ)了GridFS文件系統(tǒng)的所有文件信息)
- mongofiles -d 數(shù)據(jù)庫名字 -l "要上傳的文件的完整路徑名" put "上傳后的文件名"
# 獲取文件 (如果不寫-l以及后面的路徑參數(shù),則保存到當(dāng)前位置。)
- mongofiles -d 數(shù)據(jù)庫名字 -l "將文件保存在本地的完整路徑名" get "GridFS文件系統(tǒng)中的文件名"
#列表文件
- mongofiles -d 數(shù)據(jù)庫名字 list
#刪除文件
- mongofiles -d 數(shù)據(jù)庫名字 delete " 文件名 "
使用API
MongoDB支持多種編程語言驅(qū)動(dòng)。比如c、java、C#、NodeJS等。因此可以使用這些語言MongoDB驅(qū)動(dòng)API操作,擴(kuò)展GridFS。
以SpringBoot為例:
在 上次Mongo測試基礎(chǔ)上
官方文檔教程
上傳文件
//文件操作
@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 包下創(chuàng)建 MongoConfig 類
@Configuration
public class MongoConfig {
@Bean
public GridFsTemplate gridFsTemplate(MongoDatabaseFactory dbFactory, MongoConverter converter) {
return new GridFsTemplate(dbFactory, converter, "pictureFs");
}
}
再在測試類中上傳文件,就上傳到了pictureFs桶中
上傳文件 -法2
使用GridFSBucket.uploadFromStream 方法
可以使用 GridFSUploadOptions 來配置塊大小或包含其他元數(shù)據(jù)。
@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);
// 配置塊大小 或 包含其他元數(shù)據(jù)
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() 方法指定存儲(chǔ)桶名稱
GridFSBucket bucket=GridFSBuckets.create(mongoTemplate.getDb(),"bucketName");
bucket.find().forEach(e-> System.out.println(e.getFilename()));
}
提供設(shè)置過濾器來限制返回的結(jié)果
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 {
// 使用輸出流 設(shè)置要保存的路徑
FileOutputStream streamToDownloadTo = new FileOutputStream("D:\\Test\\downTest.zip");
// 通過Id下載文件
bucket.downloadToStream(fileId, streamToDownloadTo);
// 關(guān)閉輸出流
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);
}
以上,就學(xué)習(xí)了 GridFS在 SpringBoot 中的基本使用方法
擴(kuò)充
multer-gridfs-storage:Mul GridFS存儲(chǔ)引擎,用于Multer將上傳的文件直接存儲(chǔ)到MongoDbGitHub - devconcept/multer-gridfs-storage
gridfs-stream:輕松將文件流式傳輸?shù)組ongoDB GridFS和從MongoDB GridFS流式傳輸文件。GitHub - aheckmann/gridfs-stream
GridFS也有一些問題,
比如它讀取文件的性能并不是很好,因?yàn)槲覀冃枰樵儍纱渭希ㄏ仁莊s.files,再是fs.chunks)才能將文件拼湊出來。
如果我們的文件需要經(jīng)常修改,那么GridFS也不合適,因?yàn)镚ridFS沒法修改單獨(dú)的某個(gè)分塊,要修改文件的話,需要先將該文件刪除,然后重新上傳。