MongodbGFS存储大文件(java版)

Posted 林老师带你学编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongodbGFS存储大文件(java版)相关的知识,希望对你有一定的参考价值。

Mongodb 是一个开源的no-sql分布式数据库,Mongodb也为我们提供了基于文件的GFS分布式存储系统。因此利用Mongodb我们完全可以实现一个分布式的文件存储以及管理。

下面的内容主要为大家介绍,如何利用java,将大文件存入Mongodb数据库中。我们这里所说的大文件,是指大小在16M以上的文件,这也符合MongodbGFS的说明。

首先我们创建一个java工程,这里我们使用gradle初始化一个java工程,工程结构如下图。


当然这里你也可以使用maven来构建一个java工程,对我们后续工作并不会有影响。

接下来我们去mongodb的官网下载其基于java的驱动包。Mongodbjava驱动程序。

MongodbGFS存储大文件(java版)

这里我们只需要将这一行,复制到我们工程的build.gradle 文件。

MongodbGFS存储大文件(java版)

然后刷新gradle,我们可以看到jar包已经添加到我们的程序里。

MongodbGFS存储大文件(java版)

接下来我们编写调用的示例,我们新建一个类叫做MongdbGFS.java。然后获取一个Mongodb的连接,代码如下:


[java] view plain copy

  1. package mongodbGfs;  

  2.   

  3. import com.mongodb.MongoClient;  

  4. import com.mongodb.client.MongoDatabase;  

  5.   

  6. /** 

  7.  *  

  8.  * @author zhaotong 

  9.  * 

  10.  */  

  11. public class MongodbGFS {  

  12.       

  13.     private MongoClient mongoClient;  

  14.       

  15.     //我们进行操作的数据库  

  16.     private MongoDatabase useDatabase;  

  17.       

  18.     //初始化  

  19.     {  

  20.         mongoClient=new MongoClient("localhost",27017);  

  21.         useDatabase=mongoClient.getDatabase("zhaotong");  

  22.     }  

  23.   

  24. }  


接下来,我们先不着急写下面的代码,我们先找到一个文件放到我们工程里面,为了我们之后的测试。我在src下面新建了一个文件夹file,里面存放了一个大约21M的pdf文件。

MongodbGFS存储大文件(java版)

接下里我们开始进行mongodbGFS文件的存储。


GridFS is a specification for storing and retrieving files that exceed the BSON document size limit of 16MB. Instead of storing a file in a single document, GridFS divides a file into parts, or chunks, and stores each of those chunks as a separate document.

When you query a GridFS store for a file, the Java driver will reassemble the chunks as needed.

从上面这段话可以简单的了解到,mongodb是将文件进行分块,存储,当查询时,mongodb会帮你把你所需要的块进行组合然后展示给你,因此结合mongodb分布式的特性,我们可以轻易的构建一个分布式的文件存储。

在利用java驱动存储时,当我们获得需要存储的数据库连接之后,我们需要先创建一个bucket,官方的说明如下:


Create a GridFS Bucket


GridFS stores files in two collections: a chunks collection stores the file chunks, and a files collection stores file metadata. The two collections are in a common bucket and the collection names are prefixed with the bucket name.

通过上面的这段话,我们可以知道,mongodb是将文件分为两部分存储,一个是chunks,另一个是files。并且在collection 的名字将会有你bucket的前缀。mongodb支持自定义的bucket的名字,当然也有默认,默认是files。

[java] view plain copy

  1. @author zhaotong  

  2.  *  

  3.  */  

  4. public class MongodbGFS {  

  5.       

  6.     private MongoClient mongoClient;  

  7.       

  8.     //我们进行操作的数据库  

  9.     private MongoDatabase useDatabase;  

  10.       

  11.     //bucket  

  12.     private GridFSBucket gridFSBucket;  

  13.       

  14.     //初始化  

  15.     {  

  16.         mongoClient=new MongoClient("localhost",27017);  

  17.         useDatabase=mongoClient.getDatabase("zhaotong");  

  18.         // 自定义bucket name  

  19.         gridFSBucket= GridFSBuckets.create(useDatabase,"zt_files");  

  20.         // 使用默认的名字  

  21.         //gridFSBucket=GridFSBuckets.create(useDatabase);  

  22.     }  

  23.       

  24.   

  25. }  


接下来就是对应的具体操作,代码如下:

[java] view plain copy

  1. package mongodbGfs;  

  2.   

  3. import java.io.File;  

  4. import java.io.FileInputStream;  

  5. import java.io.FileNotFoundException;  

  6. import java.io.FileOutputStream;  

  7. import java.io.IOException;  

  8. import java.io.InputStream;  

  9. import java.nio.file.Files;  

  10. import java.util.ArrayList;  

  11. import java.util.List;  

  12.   

  13. import org.bson.Document;  

  14. import org.bson.types.ObjectId;  

  15.   

  16. import com.mongodb.Block;  

  17. import com.mongodb.MongoClient;  

  18. import com.mongodb.client.MongoDatabase;  

  19. import com.mongodb.client.gridfs.GridFSBucket;  

  20. import com.mongodb.client.gridfs.GridFSBuckets;  

  21. import com.mongodb.client.gridfs.GridFSUploadStream;  

  22. import com.mongodb.client.gridfs.model.GridFSFile;  

  23. import com.mongodb.client.gridfs.model.GridFSUploadOptions;  

  24.   

  25. /** 

  26.  *  

  27.  * @author zhaotong 

  28.  * 

  29.  */  

  30. public class MongodbGFS {  

  31.   

  32.     private MongoClient mongoClient;  

  33.   

  34.     // 我们进行操作的数据库  

  35.     private MongoDatabase useDatabase;  

  36.   

  37.     // bucket  

  38.     private GridFSBucket gridFSBucket;  

  39.   

  40.     // 初始化  

  41.     {  

  42.         mongoClient = new MongoClient("localhost"27017);  

  43.         useDatabase = mongoClient.getDatabase("zhaotong");  

  44.         // 自定义bucket name  

  45.         gridFSBucket = GridFSBuckets.create(useDatabase, "zt_files");  

  46.         // 使用默认的名字  

  47.         // gridFSBucket=GridFSBuckets.create(useDatabase);  

  48.     }  

  49.   

  50.     // 将文件存储到mongodb,返回存储完成后的ObjectID  

  51.     public ObjectId saveFile(String url) {  

  52.         InputStream ins = null;  

  53.         ObjectId fileid = null;  

  54.         // 配置一些参数  

  55.         GridFSUploadOptions options = null;  

  56.         // 截取文件名  

  57.         String filename = url.substring((url.lastIndexOf("/") + 1), url.length());  

  58.         try {  

  59.             ins = new FileInputStream(new File(url));  

  60.             options = new GridFSUploadOptions().chunkSizeBytes(358400).metadata(new Document("type""presentation"));  

  61.   

  62.             // 存储文件,第一个参数是文件名称,第二个是输入流,第三个是参数设置  

  63.             fileid = gridFSBucket.uploadFromStream(filename, ins, options);  

  64.   

  65.         } catch (FileNotFoundException e) {  

  66.             e.printStackTrace();  

  67.         } finally {  

  68.             try {  

  69.                 ins.close();  

  70.             } catch (IOException e) {  

  71.             }  

  72.         }  

  73.         return fileid;  

  74.     }  

  75.   

  76.     // 通过OpenUploadStream存储文件  

  77.     /** 

  78.      *  

  79.      * The GridFSUploadStream buffers data until it reaches the chunkSizeBytes and 

  80.      * then inserts the chunk into the chunks collection. When the 

  81.      * GridFSUploadStream is closed, the final chunk is written and the file 

  82.      * metadata is inserted into the files collection. 

  83.      *  

  84.      */  

  85.     public ObjectId saveFile2(String url) {  

  86.         ObjectId fileid = null;  

  87.         GridFSUploadStream gfsupload = null;  

  88.         // 配置一些参数  

  89.         GridFSUploadOptions options = null;  

  90.         // 截取文件名  

  91.         String filename = url.substring((url.lastIndexOf("/") + 1), url.length());  

  92.         try {  

  93.             options = new GridFSUploadOptions().chunkSizeBytes(358400).metadata(new Document("type""presentation"));  

  94.   

  95.             // 存储文件,第一个参数是文件名称,第二个是输入流,第三个是参数设置  

  96.             gfsupload = gridFSBucket.openUploadStream(filename, options);  

  97.   

  98.             byte[] data = Files.readAllBytes(new File(url).toPath());  

  99.   

  100.             gfsupload.write(data);  

  101.   

  102.         } catch (FileNotFoundException e) {  

  103.             e.printStackTrace();  

  104.         } catch (IOException e) {  

  105.             e.printStackTrace();  

  106.         } finally {  

  107.   

  108.             gfsupload.close();  

  109.             fileid = gfsupload.getObjectId();  

  110.         }  

  111.         return fileid;  

  112.     }  

  113.   

  114.     // 查询所有储存的文件  

  115.     public List<String> findAllFile() {  

  116.         List<String> filenames = new ArrayList<>();  

  117.   

  118.         gridFSBucket.find().forEach(new Block<GridFSFile>() {  

  119.   

  120.             @Override  

  121.             public void apply(GridFSFile t) {  

  122.                 filenames.add(t.getFilename());  

  123.             }  

  124.         });  

  125.   

  126.         return filenames;  

  127.     }  

  128.   

  129.     // 删除文件  

  130.     public void deleteFile(ObjectId id) {  

  131.         gridFSBucket.delete(id);  

  132.     }  

  133.   

  134.     // 重命名文件  

  135.     public void rename(ObjectId id, String name) {  

  136.         gridFSBucket.rename(id, name);  

  137.     }  

  138.   

  139.     // 将数据库中的文件读出到磁盘上,参数,文件路径  

  140.     public String downFile(String url, ObjectId id) {  

  141.         FileOutputStream out = null;  

  142.         String result=null;  

  143.         try {  

  144.             out = new FileOutputStream(new File(url));  

  145.             gridFSBucket.downloadToStream(id, out);  

  146.   

  147.         } catch (FileNotFoundException e) {  

  148.             e.printStackTrace();  

  149.         }finally {  

  150.             try {  

  151.                 out.close();  

  152.                 result=out.toString();  

  153.             } catch (IOException e) {  

  154.                 e.printStackTrace();  

  155.             }  

  156.         }  

  157.         return result;    

  158.     }  

  159.   

  160. }  


对应的单元测试类,大家可以下载运行:

[java] view plain copy

  1. import org.bson.types.ObjectId;  

  2. import org.junit.Before;  

  3. import org.junit.Ignore;  

  4. import org.junit.Test;  

  5.   

  6. import mongodbGfs.MongodbGFS;  

  7.   

  8. public class MongodbGFSTest {  

  9.       

  10.     private MongodbGFS mgfs;  

  11.       

  12.     @Before  

  13.     public void init() {  

  14.         mgfs=new MongodbGFS();  

  15.     }  

  16.       

  17.     // 测试存储  

  18.     @Ignore  

  19.     public void saveFile() {  

  20.         ObjectId id=mgfs.saveFile("src/file/2017 Alitech Archive_1.pdf");  

  21.         System.out.println(id);  

  22.     }  

  23.       

  24.     //测试存储二  

  25.     @Ignore  

  26.     public void saveFile2() {  

  27.         ObjectId id=mgfs.saveFile2("src/file/2017 Alitech Archive_1.pdf");  

  28.         System.out.println(id);  

  29.     }  

  30.       

  31.     // 测试查询所有在当前数据库存储的文件  

  32.     @Ignore  

  33.     public void findAllFile() {  

  34.         System.out.println(mgfs.findAllFile());  

  35.     }  

  36.       

  37.       

  38.     // 测试下载文件,存数据库  

  39.     @Ignore  

  40.     public void downFile() {  

  41.         System.out.println(mgfs.downFile("src/file/alibaba.pdf",new ObjectId("5a6ec218f9afa00c086d94bb")));  

  42.     }  

  43.       

  44.     // 测试删除文件  

  45.     @Ignore  

  46.     public void deleteFile() {  

  47.         mgfs.deleteFile(new ObjectId("5a6ec218f9afa00c086d94bb"));  

  48.     }  

  49.       

  50.     //测试重命名文件  

  51.     @Test  

  52.     public void rename() {  

  53.         mgfs.rename(new ObjectId("5a6ec218f9afa00c086d94bb"), "zhaotong.pdf");  

  54.     }  

  55.   

  56. }  


我们可以在管理工具中看到,我们存储的文件结构如下:


其每个块的存储如下:



以上是关于MongodbGFS存储大文件(java版)的主要内容,如果未能解决你的问题,请参考以下文章

springboot报错说 Failed to parse multipart servlet request; nested exception is java.io.IOException(代码片

在 java servlet 中流式传输大文件

56 java编程思想——创建窗口和程序片 用户接口API

加密文件之Java改进版

Java 数据存储

STM32F412应用开发笔记之六:使用片上Flash存储参数