目的
封装存储包的目的是为了更方便地在项目中对数据在不同的媒介进行存储,可能是云存储,也可以是本地存储。并且提供对对象名检测,对权限的判断,就是为了减少使用者在存储时忽略的一些问题,从而避免可能产生的错误。另外,通过配置文件的参数切换,可以在不修改代码的前提下,切换存储媒介。
若有自己的存储媒介,实现 stroage.go 里面的 interface,并且调用 storage.Register 即可。
存储媒介
目前,提供了对本地存储(fs),青云存储(qs),腾讯云(cos)存储的封装。
github 地址
https://github.com/navi-tt/storage
Interface
type Storage interface {
//把一个文件当做对象,读写即为,Get和Put
Init(cfg string) (Storage, error)
// 保存data至某个文件
Put(key string, r io.Reader, contentLength int64) error
// 根据某个文件写入到另一个文件里
PutByPath(key string, /*要带上路径,相对路径或绝对路径都行*/src string) error
// 获取语音流
FileStream(key string) (io.ReadCloser, *FileInfo, error)
// 获取数据
Get(key string, wa io.WriterAt) error
// 获取到某个文件
GetToPath(key string, /*要带上路径,相对路径或绝对路径都行*/dest string) error
// 获取文件信息 大小,修改时间,权限
Stat(key string) (*FileInfo, error)
// 删除文件
Del(key string) error
// 获取文件大小
Size(key string) (int64, error)
// 判断文件是否存在
IsExist(key string) (bool, error)
}
复制代码
提供的方法
以本地存储为例(FS),所有的范例代码都在上面的 github 上
初始化
storageType = fs
storageConf = {"BaseDir":"./testData"}
复制代码
fsStorage, err := storage.Init(cfg.storageType,cfg.storageConf)
if err != nil {
fmt.Printf("err : %s\n", err.Error())
return
}
复制代码
本地存储初始化,直接 call storage.Init()即可。如果是非封装好的 storage type,则会返回错误,无该类型,或者没有 Register 到 storage 里面。
base dir 参数主要是为了文件夹的 prefix,因为在多数情况下(根据自己写的项目),保存的路径前缀都是一样的,只是在一个根目录下有不同的文件夹分类存储。所以通过 base dir 定义,可以在后面的操作自动拼接上 base dir,而不会漏掉。当然,没有写也是没有问题的。
保存 data 至某个对象
Put(key string, r io.Reader, contentLength int64) error
put 方法从任何一个可读的 object 读取数据保存到对应的路径下面,该方法,会对存储的权限,对象名做校验,从而不用担心返回的错误是系统返回的而不知道为何。
buf := bytes.NewBuffer(nil)
buf.WriteString("this is test!")
if err := fsStorage.Put("test_fs.txt", buf, int64(buf.Len())); err != nil {
fmt.Printf("fs put err : %s\n", err.Error())
return
}
复制代码
从某个对象中读取数据,并存储到另一个对象
PutByPath(key string, src string) error
这个方法是从一个对象读取数据,然后存到对应的路径下面。这个方法会检查 src 是否存在,如果不存在也直接返回错误。src 的地址必须是相对路径或者是绝对路径,这个 src 不会拼上 base dir。
err := fsStorage.PutByPath("test_fs_put_by_path.txt", "../testdata/test_fs.txt")
if err != nil {
return er
}
复制代码
获取文件流
FileStream(key string) (io.ReadCloser, *FileInfo, error)
如果对象内容为空会返回对象内容为空的错误
fd,stat,err := fsStorage.FileStraem("test_fs_put_by_path.txt")
if err != nil {
return err
}
复制代码
获取对象
Get(key string, wa io.WriterAt) error
Get 方法从一个 object 获取数据并写入到一个 writeAter。
fd, _ := os.OpenFile("test.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0766)
err := fsStorage.Get("test_fs_put_by_path.txt", fd)
if err != nil {
return err
}
defer fd.close()
复制代码
获取对象到指定对象
GetToPath(key string, dest string) error
GetToPath 方法从一个 object 写入到另一个对象,这个方法分别会对这两个路径做权限,对象名校验。dest 的地址必须是相对路径或者是绝对路径,这个 dest 不会拼上 base dir。
if err := fsStorage.GetToPath("test_fs_put_by_path.txt", "../test.txt") ; err != nil {
复制代码
获取对象信息
Stat(key string) (*FileInfo, error)
if err := fsStorage.GetToPath("test_fs_put_by_path.txt", "../test.txt") ; err != nil {
return err
}
复制代码
stat,err := fsStorage.Stat("test_get_to_path.txt");
if err != nil {
return err
}
fmt.Sprintf("%v\n",stat)
复制代码
删除对象
Del(key string) error
Del 方法如果删除的是一个没有权限的或者不存在的文件,也会返回相应的 error
if err := fsStorage.Del("test_get_to_path.txt"); err != nil {
return err
}
复制代码
获取对象大小
Size(key string) (int64, error)
会先判断对象是否存在,如果不存在会返回相应错误
size,err := fsStorage.Size("test_get_to_path.txt");
if err != nil {
return err
}
fmt.Println(size)
复制代码
判断对象是否存在
IsExist(key string) (bool, error)
exist, err := fsStorage.IsExist("test.txt")
if err != nil {
return err
}
fmt.Sprintf("%v\n",exist)
复制代码
RoadMap
把 string 格式的 config 改成,通过配置文件直接匹配的方式,更加方便;
提供主要存储和次要存储的绑定,在项目里可以使用多个存储;
Others
storage 基于朋友 ymc 的基础上再次封装修改
欢迎指点和吐槽
评论