Java API 从 GridFS 中下载文件
GridFS 文件下载
GridFs 简介
我们在使用MongoDB存储文件的过程中,由于单个 bson 具有大小限制,因此我们不能存储大于这个上限的文件,GridFs 将文件分为若干部分(chunk),每个部分存储为一个独立的document,GridFs 默认的 chunk size 是 255kB,也就是说它将文件按255kB等分,最后一个 chunk 是不足的部分,可能不足 255kB;如果一个文件不足一个 chunk 的大小,那么就存储在一个 chunk,这个里面包含了文件和一些元数据。
GridFs 的优点
- 文件的大小超出了 16M 由于单个 bson 大小的限制,因而将文件存放于 GridFs 中。
- 对于大文件,读取时不想将整个文件载入内存中 由于文件时存放在多个 chunk 中的,读取文件的时候可以部分载入,同时访问文件的时候可以任意跳转,直接跳过某些部分请求感兴趣的部分。例如视频、音频文件。
- 在多个系统间共享文件 搭建 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();