MongoDB GridFS介绍

GridFS 用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频、视频等)。

GridFS 会将大文件对象分割成多个小的chunk(文件片段),一般为256k/个,每个chunk将作为MongoDB的一个文档(document)被存储在chunks集合中。
GridFS 用两个集合来存储一个文件:fs.files与fs.chunks。
每个文件的实际内容被存在chunks(二进制数据)中,和文件有关的meta数据(filename,content_type,还有用户自定义的属性)将会被存在files集合中。
GridFS文件内容

fs.files 集合
fs.chunks 集合

go中使用

1. 增加文件

// 输入文件名,将文件保存在MongoDB GridFS中,返回文件ID和错误码
func SaveFile(filename string) (fileId string, err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 在file前缀的GridFS中创建新文件
	file, err := db.GridFS("file").Create(filename)
	if err != nil {
		return
	}
	defer file.Close()

	// 读取文件内容
	data, err := os.OpenFile(filename, os.O_RDWR, 0666)
	if err != nil {
		return
	}
	defer data.Close()

	// 写入GridFS文件,这里也可以直接用[]byte字节流的文件
	_, err = io.Copy(file, data)
	if err != nil {
		return
	}

	// 以字符串形式返回文件ID
	fileId = file.Id().(bson.ObjectId).Hex()
	return
}

2. 查询文件

// 输入数据库中文件ID和要保存的文件名,将数据库在文件存回本地,返回错误码
func LoadFile(fileId, filename string) (err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 通过文件名获取文件,文件名不唯一,如果存在同名的,返回最后上传的那一个
	// file, err := db.GridFS("file").Open(filename)
	// 通过文件ID获取文件,因为文件ID是唯一的
	file, err := db.GridFS("file").OpenId(bson.ObjectIdHex(fileId))
	if err != nil {
		return
	}
	defer file.Close()

	// 读取文件内容
	data, err := os.OpenFile(filename, os.O_CREATE, 0666)
	if err != nil {
		return
	}
	defer data.Close()

	// 将数据写入文件
	_, err = io.Copy(data, file)
	if err != nil {
		return
	}

	return
}

3. 删除文件

// 删除文件,输入文件ID
func RemoveFile(fileId string) (err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 如果是文件名删,则删除所有同名的文件
	// err = db.GridFS("file").Remove(filename)
	// 通过文件ID删除文件
	err = db.GridFS("file").RemoveId(bson.ObjectIdHex(fileId))
	return
}

4. 完整代码测试

package main

import (
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io"
	"os"
)

func main() {
	fileId, err := SaveFile("test.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	
	fmt.Println(fileId)

	err = LoadFile(fileId, "test1.txt")
	if err != nil {
		fmt.Println(err)
		return
	}

	err = RemoveFile(fileId)
	if err != nil {
		fmt.Println(err)
		return
	}
}

// 输入文件名,将文件保存在MongoDB GridFS中,返回文件ID和错误码
func SaveFile(filename string) (fileId string, err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 在file前缀的GridFS中创建新文件
	file, err := db.GridFS("file").Create(filename)
	if err != nil {
		return
	}
	defer file.Close()

	// 读取文件内容
	data, err := os.OpenFile(filename, os.O_RDWR, 0666)
	if err != nil {
		return
	}
	defer data.Close()

	// 写入GridFS文件,这里也可以直接用[]byte字节流的文件
	_, err = io.Copy(file, data)
	if err != nil {
		return
	}

	// 以字符串形式返回文件ID
	fileId = file.Id().(bson.ObjectId).Hex()
	return
}

// 输入数据库中文件ID和要保存的文件名,将数据库在文件存回本地,返回错误码
func LoadFile(fileId, filename string) (err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 通过文件名获取文件,文件名不唯一,如果存在同名的,返回最后上传的那一个
	// file, err := db.GridFS("file").Open(filename)
	// 通过文件ID获取文件,因为文件ID是唯一的
	file, err := db.GridFS("file").OpenId(bson.ObjectIdHex(fileId))
	if err != nil {
		return
	}
	defer file.Close()

	// 读取文件内容
	data, err := os.OpenFile(filename, os.O_CREATE, 0666)
	if err != nil {
		return
	}
	defer data.Close()

	// 将数据写入文件
	_, err = io.Copy(data, file)
	if err != nil {
		return
	}

	return
}

// 删除文件,输入文件ID
func RemoveFile(fileId string) (err error) {
	// 连接数据库
	session, err := mgo.Dial("mongodb://root:guoke3915@127.0.0.1:3717/admin")
	defer session.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	// 获取Test库
	db := session.DB("Test")

	// 如果是文件名删,则删除所有同名的文件
	// err = db.GridFS("file").Remove(filename)
	// 通过文件ID删除文件
	err = db.GridFS("file").RemoveId(bson.ObjectIdHex(fileId))
	return
}