19 KiB
title | date | author | tags | categories | ||||
---|---|---|---|---|---|---|---|---|
MongoDB GridFS文件存储 | 2021-01-28 | ac |
|
|
GIS中遥感影像数据可以使用MongoDB的GridFS进行存储。
1 GridFS
简介
GridFS
文件系统是MongoDB
存储大文件的一种规范,所有官方的MongoDB
驱动都遵循该规范。它解决了BSON
文档大小不能超过16M的问题。
GridFS
不是将文件存储在单个文档中,而是将文件分成多个数据块,并将每个块存储为单独的文档。默认情况下,GridFS
使用的默认数据块大小为255 kB;也就是说,除了最后一个数据块外,GridFS
将一个文件划分为255 kB的小块。
GridFS
使用两个集合来存储文件。一个集合存储文件的数据块,另一个集合存储文件元数据,像文件名称、大小、创建日期等。
当您在使用GridFS
查询文件时,会根据需要重新组装这些数据块。另外GridFS
不仅可以存储操过16MB的文件,还可以访问大文件的部分信息而不必将整个文件加载到内存中。
使用GridFS
的方式有以下两种:
-
使用程序接口的方式,利用
MongoDB
对各程序语言的提供的驱动对文件进行操作。 -
使用
mongofiles
命令行工具。
2 GridFS
集合
GridFS
将文件存储在两个集合中:
chunks
:存储二进制块files
:存储文件的元数据
GridFS
通过在每个集合前面加上前缀,将这两个集合放在一个公共容器:bucket(命名空间)中。默认情况下,GridFS
使用两个集合,一个容器名为fs
:
fs.files
fs.chunks
官方的英语文档描述的更加形象:The two collections are in a common bucket and the collection names are prefixed with the bucket name.
2.1 chunks集合
{
"_id" : <ObjectId>,
"files_id" : <ObjectId>,
"n" : <num>,
"data" : <binary>
}
ObjectId
: 一种特殊的BSON类型,它保证集合内的唯一性。
ObjectId
值的长度为12个字节,包括: 4 byte 时间戳、5 byte 随机数 、3 byte 增长量
- chunks._id:数据块的标识
- chunks.files_id:所属文件的标识
- chunks.n: 块的序列号。
GridFS
给所有块编号,从0开始。 - chunks.data :数据块中装载的数据,Binary类型。
2.2 files集合
{
"_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: 每个块的大小(以字节为单位)。GridFS将文档分成大小为chunkSize的块,但最后一个块的大小仅根据需要而定。默认大小是255kb。
- files. uploadDate : 文件第一次被GridFS存储的日期。该值具有日期类型。
- files.md5: MD5算法被FIPS 140-2禁止。MongoDB驱动程序已弃用MD5支持,并将在未来版本中删除MD5生成。需要文件摘要的应用程序应该在GridFS之外实现它,并存储在files.metadata中。
- files.filename: 可读的GridFS文件名称。
- files.metadata: 可选的。元数据字段可以是任何数据类型,可以保存您想要存储的任何附加信息。
3 mongofiles
工具
3.1 mongofiles
作用
mongofiles
工具可以通过命令行操作MongoDB
实例中GridFS
对象中存储的文件。它提供了存储在文件系统和GridFS
中的对象之间的接口。
从
MongoDB
4.4 开始,mongofiles
从MongoDB
服务器单独发布,并使用自己的版本控制,初始版本为100.0.0。在此之前,mongofiles
是与MongoDB
一起发布的,并使用了匹配的版本控制。
3.2 安装 mongofiles
根据之前安装MongoDB
实例,选择下载工具的版本。之前MongoDB
使用的是zip
免安装的形式,所以这里下载mongodb-database-tools-windows-x86_64-100.2.zip
。
将下载的文件解压到任意位置,再将mongofiles
工具目录下的bin
目录添加到系统的Path
环境变量中。
qiusj@u20:~$ cat /etc/os-release
NAME="Pop!_OS"
VERSION="20.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
LOGO=distributor-logo-pop-os
#查看Linux内核版本
qiusj@u20:~$ arch
x86_64
下载合适的版本,可以下载后使用sftp
传输到Linux,也可以使用curl
命令下载:
$ curl -o mongodb-database-tools.tgz https://fastdl.mongodb.org/tools/db/mongodb-database-tools-ubuntu2004-x86_64-100.2.1.tgz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 64.0M 100 64.0M 0 0 1222k 0 0:00:53 0:00:53 --:--:-- 2106k
$ ll
总用量 128560
drwxr-xr-x 5 qiusj intplanet 4096 1月 28 17:00 ./
drwxr-xr-x 6 qiusj intplanet 4096 1月 5 09:42 ../
-rw-r--r-- 1 qiusj intplanet 67211368 1月 28 17:00 mongodb-database-tools.tgz
#解压
$ tar -zxvf mongodb-database-tools.tgz
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/LICENSE.md
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/README.md
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/THIRD-PARTY-NOTICES
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/bsondump
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongodump
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongoexport
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongofiles
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongoimport
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongorestore
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongostat
mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin/mongotop
#将解压的文件bin目录下的命令复制到/usr/local/bin/目录下
$ cd mongodb-database-tools-ubuntu2004-x86_64-100.2.1/bin
$ sudo cp * /usr/local/bin
$ mongofiles --version
mongofiles version: 100.2.1
git version: 0cb6f592fcb425ee5b3d5540341de75531d28dac
Go version: go1.12.17
os: linux
arch: amd64
compiler: gc
3.3 基本使用
mongofiles
命令的语法格式如下:
mongofiles <options> <connection-string> <command> <filename or _id>
options
主要配置mongofiles
的一些读写优先级。connection-string
是连接mongod/mongos
的配合信息,如host、port、安全认证等相关配置。command
是mongofiles
具体的文件操作,如导入、导出、查询等。
对于副本集,
mongofiles
只能从主节点读。当启动安全认证后,
mongofiles
连接的用户需要有read
权限(list
、earch
、get
等命令)和readWrite
权限(put
、delete
等命令)
常用Options配置项:
options | description |
---|---|
--help | 返回 mongofiles 的配置项和使用信息 |
--version | 返回 mongofiles 的版本信息 |
--uri | 指定MongoDB 的连接信息,如: --uri="mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]" |
--config | 指定配置文件,以配置文件的形式启动 |
**Commands: **
命令 | 说明 |
---|---|
list <prefix> | 列出GridFS 存储的文件。<prefix>用于筛选返回列表中以 prefix字符串为前缀的文件。 |
search <string> | 列出GridFS 中名称与<string>的任何部分匹配的文件。 |
put <filename1[ filename2] ...> | 将指定的文件从本地文件系统复制到GridFS 中。多个文件可以指定为空格分隔的列表。 |
get <filename1[ filename2] ...> | 将指定的文件从GridFS 存储复制到本地文件系统。 |
get_id "<_id>" | 将文件(由<_id>指定)从GridFS 中复制到本地文件系统。<_id>是该对象在GridFS 中的扩展JSON _id。 |
get_regex <regex> --regexOptions <regex-options> | 将匹配指定的<regex>表达式的一个或多个文件从GridFS 复制到本地文件系统。get_regex命令使用Perl兼容的正则表达式(“PCRE”)8.42版本,支持UTF-8。 |
delete <filename> | 从GridFS 中删除指定的文件 |
delete_id "<_id>" | 从GridFS 中删除由<_id>指定的文件。 |
3.4 示例
在系统的命令行中运行 mongofiles
命令:
# 查看本地mongofiles实例执行过的历史命令
mongofiles -d=records list
导入文件,下面命令mongofiles
实例将连接 uri
中的数据库,将文件存入GridFS
中。
$ mongofiles --uri=mongodb://192.168.0.152:27017 put /home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif
2021-03-04T17:18:06.681+0800 connected to: mongodb://192.168.0.152:27017
2021-03-04T17:18:06.682+0800 adding gridFile: /home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif
2021-03-04T17:18:06.824+0800 added gridFile: /home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif
查看集合:
#连接数据库
$ /usr/local/mongodb/bin/mongo --host=192.168.0.152 --port=27017
#查看数据库
> db
test
#查看集合
> show collections
fs.chunks
fs.files
#查看files集合
> db.fs.files.find()
{
"_id" : ObjectId("6040a5ce6211dcaf818ac9aa"),
"length" : NumberLong(15838376),
"chunkSize" : 261120,
"uploadDate" : ISODate("2021-03-04T09:18:06.824Z"),
"filename" : "/home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif",
"metadata" : { }
}
查询文件:
$ mongofiles search 'Cho'
2021-03-04T17:48:10.976+0800 connected to: mongodb://localhost/
/home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif 15838376
搜索结果:filename length
可以发现mongofiles命令默认连接本地的 mongo 服务,如果不是本地需带上 uri 连接信息。
获取文件:
$ mongofiles --uri=mongodb://localhost:27017 get /home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif --local=test.tif
2021-03-04T17:57:34.507+0800 connected to: mongodb://localhost:27017
2021-03-04T17:57:34.531+0800 finished writing to test.tif
get <filename1[ filename2] ...>命令,当只有一个文件时,可以使用--local参数给文件重新命名。
导出的目录为get命令执行所在的当前目录。
删除文件:
$ mongofiles delete /home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif
2021-03-04T18:03:23.399+0800 connected to: mongodb://localhost/
2021-03-04T18:03:23.402+0800 successfully deleted all instances of '/home/qiusj/.local/mongodb/mongofiles/data/shenzhen_CholophyII_2020.tif' from GridFS
#再去数据库里查看
$ /usr/local/mongodb/bin/mongo
> show collections
fs.chunks
fs.files
> db.fs.files.find()
>
4 Springboot中使用GridFS
使用一个单实例的未启用认证的mongodb
作为示例数据库。
4.1 导入依赖
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4.2 配置文件
application.yml
文件:
#如果连接的不是本地的mongo,会比较慢,因为会受到网络传输速度的影响
spring:
data:
mongodb:
database: files
host: localhost
port: 27017
#用于测试的本地遥感数据文件
rsfilepath: "E:\\data\\ShenzhenNDWI_2019_S2L1C.tif"
MongoConfig.java
,在该类中根据配置信息创建mongo
的客户端实例和GridFSBucket
实例。
GridFS
用于存储文件的两个集合都在同一个bucket
中。集合的前缀为bucket name
,默认为fs
。
@Configuration
public class MongoConfig {
@Value("${spring.data.mongodb.host}")
private String host;
@Value("${spring.data.mongodb.port}")
private int port;
@Value("${spring.data.mongodb.database}")
private String database;
@Bean
public MongoClient getMongoClient(){
MongoClient mongoClient = MongoClients.create(
MongoClientSettings.builder()
.applyToClusterSettings(builder ->
builder.hosts(Arrays.asList(
new ServerAddress(host, port)
)))
.build());
return mongoClient;
}
@Bean
public GridFSBucket getgridFSBucket(MongoClient mongoClient) {
MongoDatabase mongoDatabase = mongoClient.getDatabase(database);
//使用默认的fs前缀
GridFSBucket gridFSBucket = GridFSBuckets.create(mongoDatabase);
return gridFSBucket;
}
}
4.3 测试类
我们在Test模块下创建一个GridsApplicationTests.java
测试类,用于测试GridFSBucket
中的方法:
@SpringBootTest
class GridfsApplicationTests {
@Autowired
private GridFSService gridFSService;
@Value("${rsfilepath}")
private String rsfilepath;
private int chunckSize = 1024;
@Autowired
private GridFSBucket gridFSBucket;
/**
* uploadFromStream()方法
* 文件导入到GridFS中
*/
@Test
void testUploadToGridFS() throws IOException {
File file = new File(rsfilepath);
FileInputStream inputStream = new FileInputStream(file);
//GridFSUploadOptions配置chunkSize和添加元数据
GridFSUploadOptions options = new GridFSUploadOptions()
.chunkSizeBytes(chunckSize)
.metadata(new Document("k1","v1").append("k2","v2"));
//GridFSBucket.InputStream方法读取字节输入流中的内容并将其保存到GridFSBucket中
ObjectId fileId = gridFSBucket.uploadFromStream("GridFS输入", inputStream, options);
System.out.println(fileId);
inputStream.close();
}
/**
* openUploadStream()方法
* 返回GridFSUploadStream,作为缓存
* 文件导入到GridFS中
*/
@Test
void testUOpenploadToGridFS() throws IOException {
byte[] data = Files.readAllBytes(Paths.get(rsfilepath));
//GridFSUploadOptions 配置 chunkSize 和添加元数据
GridFSUploadOptions options = new GridFSUploadOptions()
.chunkSizeBytes(chunckSize)
.metadata(new Document("format","tiff").append("SRS","EPSG:3857"));
GridFSUploadStream uploadStream = gridFSBucket.openUploadStream("缓冲", options);
//GridFSUploadStream缓冲数据达到chunckSizeBytes时才进行插入数据块chunks操作
uploadStream.write(data);
//当GridFSUploadStream被关闭后,才会将最后一块chunk写入chunks集合和将文件元数据插入files集合
uploadStream.close();
String fileId = uploadStream.getObjectId().toString();
System.out.println(fileId);
}
/**
* find()方法
* 查找GridFS中的文件
*/
@Test
void testFindFileFromGridFS() throws IOException {
//查询GridFS中所有的文件
gridFSBucket.find().forEach(gridFSFile -> {
System.out.println(gridFSFile.getObjectId()+": "+gridFSFile.getFilename());
});
System.out.println("-----------------------");
gridFSBucket.find(eq("metadata.SRS","EPSG:3857")).forEach(gridFSFile -> {
System.out.println(gridFSFile.getObjectId()+": "+gridFSFile.getFilename());
});
}
/**
* downloadToStream()方法
* 根据fileId从GridFS中下载文件
*/
@Test
void testDownloadToStreamById() throws IOException {
//需要导出的文件的fileId
ObjectId fileId = new ObjectId("6049d240efdc5715fc6ecbbe");
//指定输出目标路径和输出文件名
File file = new File("E:\\data\\out\\NDWI_2019_S2L1C.tiff");
if(!file.exists()){
file.getParentFile().mkdirs();
file.createNewFile();
}
//创建文件字节输出流
FileOutputStream out = new FileOutputStream(file);
gridFSBucket.downloadToStream(fileId, out);
out.close();
}
/**
* downloadToStream()方法
* 根据filename从GridFS中下载文件
*/
@Test
void testDownloadToStreamByFilename() throws IOException {
//创建下载条件对象
GridFSDownloadOptions downloadOptions = new GridFSDownloadOptions();
/**
* 版本控制,默认下载最新的一个版本对象,这里指定为0,选择原始的版本
* 0 = the original stored file
* 1 = the first revision
* 2 = the second revision
* etc..
* -2 = the second most recent revision
* -1 = the most recent revision
*/
downloadOptions.revision(0);
//指定输出目标路径和输出文件名
File file = new File("E:\\data\\out\\NDWI2.tiff");
if(!file.exists()){
file.getParentFile().mkdirs();
file.createNewFile();
}
//创建文件字节输出流
FileOutputStream out = new FileOutputStream(file);
gridFSBucket.downloadToStream("归一化指数2019",out,downloadOptions);
out.close();
}
/**
* rename,重命名
*/
@Test
void testRenameFile(){
ObjectId fileId = new ObjectId("6049d240efdc5715fc6ecbbe");
gridFSBucket.rename(fileId,"归一化指数2019");
}
/**
* delete
*/
@Test
void testDeleteFile(){
ObjectId fileId = new ObjectId("6049bf658ca88237b95c9952");
gridFSBucket.delete(fileId);
}
}
参考文章
[1] GridFS
https://docs.mongodb.com/manual/core/gridfs/
[2] mongofiles
https://docs.mongodb.com/database-tools/mongofiles
[3] Java Driver Tutorial GridFS
https://mongodb.github.io/mongo-java-driver/4.2/driver/tutorials/gridfs/