MogoDB 文件的上传与下载 GridFS 的使用

GridFS — MongoDB Manual

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没法修改单独的某个分块,要修改文件的话,需要先将该文件删除,然后重新上传。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。