Java API 从 GridFS 中下载文件

GridFS 文件下载

GridFs 简介

我们在使用MongoDB存储文件的过程中,由于单个 bson 具有大小限制,因此我们不能存储大于这个上限的文件,GridFs 将文件分为若干部分(chunk),每个部分存储为一个独立的document,GridFs 默认的 chunk size 是 255kB,也就是说它将文件按255kB等分,最后一个 chunk 是不足的部分,可能不足 255kB;如果一个文件不足一个 chunk 的大小,那么就存储在一个 chunk,这个里面包含了文件和一些元数据。

GridFs 的优点

  1. 文件的大小超出了 16M 由于单个 bson 大小的限制,因而将文件存放于 GridFs 中。
  2. 对于大文件,读取时不想将整个文件载入内存中 由于文件时存放在多个 chunk 中的,读取文件的时候可以部分载入,同时访问文件的时候可以任意跳转,直接跳过某些部分请求感兴趣的部分。例如视频、音频文件。
  3. 在多个系统间共享文件 搭建 Mongo 集群,在集群间共享文件。

文件存储结构

files collection

files 这个集合里面的每一条记录代表了 GridFs 中的一个文件

{
    "_id": <objectId>,
    "length": <num>,
    "chunkSize": <num>,
    "uploadDate": <timestamp>,
    "md5": <hash>,
    "filename": <string>,
    "contentType": <string>,
    "aliases": <string array>,
    "metadata": <any>,
}
  • files._id 文档唯一标识
  • files.length 文件长度
  • files.chunkSize 每个 chunk 的大小
  • files.uploadDate 文件上传时间
  • files.metadata 额外的元数据,可以存放自定义的一些标识。

chunks collection

chunk 结构

{
    "_id": <ObjectId>,
    "files_id": <ObjectId>,
    "n": <num>,
    "data": <binary>
}
  • chunks._id chunk 的唯一标识
  • chunks.files_id 文件的 id, 对应到 chunk 归属文件的 _id。
  • chunks.n 此 chunk 是文件的额第几个 chunk,从 0 开始。
  • chunks.data chunk 里面的数据,以 BSON 形式存放。

调用 Java api 从 GridFS 下载文件

    MongoClient mongoClient = new MongoClient(new ServerAddress(<host>, <port>));
    MongoDatabase db = mongoClient.getDatabase(<databaseName>);
    GridFSBucket bucket = GridFSBucket.create(db, <bucketName>);
    // 下载到文件中
    FileOutputStream out = new FileOutputStream(<filename>);
    bucket.downloadToStream(new ObjectId(<id>), out);
    out.flush();
    out.close();

从 mongo 的 GridFSBucket 中打开一个 stream 的时候要注意,如果这个文件存在于多个 chunk 中,无法一次性读取全部数据,必须 分次读取。

    MongoClient mongoClient = new MongoClient(new ServerAddress(<host>, <port>));
    MongoDatabase db = mongoClient.getDatabase(<databaseName>);
    GridFSBucket bucket = GridFSBucket.create(db, <bucketName>);
    GridFSDownloadStream stream = bucket.openDownloadStream(new Object(<id>));
    ByteArrayOutputStream os = new ByteArrayOutputStream(stream.available());
    byte[] bytes = new byte[1024];
    int size;
    while ((size = stream.read(bytes)) > 0) {
      os.write(bytes, 0, size);
    }
    bytes = os.toByteArray();
    FileOutputStream fos = new FileOutputStream(fileName);
    fos.write(bytes);
    stream.close();
    os.close();
    fos.close();

引用

GridFSDownloadStream can not read all data


2019-07-14 17:20 +0800