一 简介
    GridFS是MongoDB中存储和查询超过BSON文件大小限制(16M)的规范,不像BSON文件那样在一个单独的文档中存储文件,GridFS将文件分成多个块,每个块作为一个单独的文档。默认情况下,每个GridFS块是255kB,意味着除了最后一个块之外(根据剩余的文件大小),文档被分成多个255kB大小的块存储。    GridFS使用两个集合保存数据,一个集合        存储文件块,另外一个存储文件元数据。当从GridFS中获取文件时,MongoDB的驱动程序负责将多个块组装成完整文件,你可以通过GridFS进行范围查询,可以访问文件的任意部分        (例如跳到视频文件或者音频文件的任意位置)。无论是超过16M的文件和其他文件,只要存在访问时不想加载整个文件的场景存在,GridFS就有帮助。


二 应用场景
    在MongoDB中,使用GridFS存储超过16M的文件(BSON文件不能超过16M)。在某些情况下,MongoDB存储大文件会比操作系统的文件系统更高效:
        1. 如果你的文件系统限制目录下文件的个数,可以使用MongoDB在目录下存储任意多的文件。
        2. 访问大数据文件时,不想一次加载而是分段访问。
        3. 在多个系统间实现文件和元数据同步。
        对文件进行原子更新时,MongoDB不适合,不能支持对文件多个块更新操作的原子性;如果确有需要,也可以通过在元数据中指定当前版本来变通实现。        如果你的文件都小于16M,应该考虑使用每个文件存一个独立文档的方式来取代GridFS,可以使用BinData类型来存储二进制数据(也可以使用GridFS,需要修改chunk大小,避免小文件        被拆分,需要进行测试和比较性能)。


三 存储管理
    MongodB使用两个集合来存储GridFS文件,一个是fs.files,另一个是fs.chunks。
        fs.files这个集合中存储的是每一个上传到数据库的文档的信息。
        fs.chunks这个集合存储的是上传文件的内容。一个chunk相当于一个文档(大文件被拆分成多个有序的chunk)。
        GridFS中的bucket这个概念指代的是fs.files和fs.chunks的组合。
        
四 基于spring boot,实现GridFS的基本操作。

[Java] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@RestController
    @RequestMapping("/api")
    public class GridFSApi {
     private static Logger LOGGER = Logger.getLogger(GridFSApi.class);
     @Autowired
     private GridFsTemplate gridFsTemplate;
  
     @RequestMapping(value = "/save", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
     public Response save(@RequestParam(value = "file", required = true) MultipartFile file) {
  
         LOGGER.info("Saving file..");
         DBObject metaData = new BasicDBObject();
         metaData.put("createdDate", new Date());
  
         String fileName = UUID.randomUUID().toString();
  
         LOGGER.info("File Name: " + fileName);
  
         InputStream inputStream = null;
         try {
             inputStream = file.getInputStream();
             gridFsTemplate.store(inputStream, fileName, "image", metaData);
             LOGGER.info("File saved: " + fileName);
         } catch (IOException e) {
             LOGGER.error("IOException: " + e);
             throw new RuntimeException("System Exception while handling request");
         }
         LOGGER.info("File return: " + fileName);
         return new Response(fileName);
     }
  
     @RequestMapping(value = "/get", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
     public byte[] get(@RequestParam(value = "fileName", required = true) String fileName) throws IOException {
         LOGGER.info("Getting file.." + fileName);
         List<GridFSDBFile> result = gridFsTemplate
                 .find(new Query().addCriteria(Criteria.where("filename").is(fileName)));
         if (result == null || result.size() == 0) {
             LOGGER.info("File not found" + fileName);
             throw new RuntimeException("No file with name: " + fileName);
         }
         LOGGER.info("File found " + fileName);
         return IOUtils.toByteArray(result.get(0).getInputStream());
     }
  
     @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
     public void delete(@RequestParam(value = "fileName", required = true) String fileName) {
         LOGGER.info("Deleting file.." + fileName);
         gridFsTemplate.delete(new Query().addCriteria(Criteria.where("filename").is(fileName)));
         LOGGER.info("File deleted " + fileName);
     }
 }