问题
腾讯云的对象存储可以看做是一个线上的KV,因为最近有需求所以试着用了一下。在使用的时候遇到了一些问题,具体来说是cos.BucketGetOptions
中的Delimiter的使用问题。
- 列出对象中使用的Delimiter为"/"
- 下载对象中使用的Delimiter为""
按官方的说法,delimiter表示列出当前目录下的object,设置为空的时候列出所有的object。我不太清楚这个所有具体是什么意思,因此还是实践了一下。
实践与代码
代码与腾讯cos Go SDK使用学习比较类似,本身应该没有难度。
代码包含以下内容:
- 环境构造:通过批量上传文件来构建复杂的文件环境,为后续获取与下载文件提供基础
- 文件下载:测试文件内容是否符合预期
- 文件批量下载:测试delimiter选项在下载中的影响
- 文件列出:测试delimiter选项在文件列出中的影响
环境构造
使用以下函数构造环境,注意:腾讯云对象存储不是免费服务,使用时注意费用情况。本文示例的文件操作理论上不会超过免费限制,但在修改代码的时候请注意。
代码语言:go复制func main(){
u, _ := url.Parse("https://wtytest-1252789333.cos.ap-guangzhou.myzijiebao.com")
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
// 通过环境变量获取密钥
// 环境变量 COS_SECRETID 表示用户的 SecretId,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
SecretID: "secretID",
// 环境变量 COS_SECRETKEY 表示用户的 SecretKey,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
SecretKey: "secret",
// Debug 模式,把对应 请求头部、请求内容、响应头部、响应内容 输出到标准输出
Transport: &debug.DebugRequestTransport{
RequestHeader: true,
RequestBody: true,
ResponseHeader: true,
ResponseBody: false,
},
},
})
// 1. 批量上传文件,构建测试集合
uploadFileToCos(0, "", c)
}
func uploadFileToCos(depth int, prefix string, c *cos.Client) {
if depth > 5 {
return
}
for i := 0; i < 3; i {
s := rand.Intn(100)
filePath := prefix "file" strconv.Itoa(s)
err := uploadFileByName(filePath, "file" strconv.Itoa(s), c)
if err != nil {
log_status(err)
}
}
for i := 0; i < 2; i {
s := rand.Intn(100)
filePrefix := prefix "path" strconv.Itoa(s) "/"
uploadFileToCos(depth 1, filePrefix, c)
}
}
文件下载
代码语言:go复制// 随便选一个文件名,测试一下是否成功写入
//getFileByName("path59/file81", c)
// 结果为content: file81
func getFileByName(name string, c *cos.Client) {
resp, err := c.Object.Get(context.Background(), name, nil)
log_status(err)
bs, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
fmt.Println("content:", string(bs))
}
文件批量下载
代码语言:go复制func main(){
const NoDelimiter = ""
const FolderDelimiter = "/"
const path1 = "path59/path33/path43/" // 测试末尾为/
const path2 = "path59/path33/path43" // 测试末尾不为/
getAllFileInPrefix(path1, NoDelimiter, c)
getAllFileInPrefix(path1, FolderDelimiter, c)
}
func getAllFileInPrefix(prefix string, delimiter string, c *cos.Client) {
totalFileCount := 0
isTruncated := true
marker := ""
count := 0
for isTruncated {
fmt.Printf("count:%d marker:%s isTruncated:%v", count, marker, isTruncated)
count
opt := &cos.BucketGetOptions{
Prefix: prefix,
Marker: marker,
Delimiter: delimiter,
}
v, _, err := c.Bucket.Get(context.Background(), opt)
if err != nil {
log_status(err)
return
}
for _, content := range v.Contents {
resp, err := c.Object.Get(context.Background(), content.Key, nil)
if err != nil {
log_status(err)
return
}
bs, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
fmt.Printf("key:%s content:%sn", content.Key, string(bs))
totalFileCount
}
marker = v.NextMarker
isTruncated = v.IsTruncated
}
fmt.Println("total file count is ", totalFileCount, " with count:", count)
}
当cos的键的前缀末尾有"/"时,采用NoDelimiter能获得21个文件,采用FolderDelimiter能获得3个文件。
当cos的键的前缀末尾没有"/"时,采用NoDelimiter能获得21个文件,采用FolderDelimiter能获得0个文件。
这说明delimiter为"/"的时候可以理解为文件夹模式,文件夹模式只对模拟出的文件夹(即前缀末尾有"/")起作用。
如果delimiter为空字符串的时候则会尝试匹配前缀相同的对象。
文件列出
文件列出与文件下载开始的一段逻辑有点类似,不过加上了commonPrefix。测试代码与此前相同,此处不再赘述。
代码语言:go复制func listAllFileInPrefix(prefix string, delimiter string, c *cos.Client) {
var marker string
opt := &cos.BucketGetOptions{
Prefix: prefix,
Delimiter: delimiter,
MaxKeys: 1000,
}
totalFileCount := 0
commonPrefixCount := 0
isTruncated := true
for isTruncated {
opt.Marker = marker
v, _, err := c.Bucket.Get(context.Background(), opt)
if err != nil {
fmt.Println(err)
break
}
for _, content := range v.Contents {
fmt.Printf("Object: %vn", content.Key)
}
totalFileCount = len(v.Contents)
// common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
for _, commonPrefix := range v.CommonPrefixes {
fmt.Printf("CommonPrefixes: %vn", commonPrefix)
}
commonPrefixCount = len(v.CommonPrefixes)
isTruncated = v.IsTruncated // 是否还有数据
marker = v.NextMarker // 设置下次请求的起始 key
}
fmt.Println("total file count", totalFileCount, " commonPrefix:", commonPrefixCount)
}
当cos的键的前缀末尾有"/"时,采用NoDelimiter能获得21个文件且没有截断路径,采用FolderDelimiter能获得3个文件并截断了2个路径(当前目录下的两个子目录)。
当cos的键的前缀末尾没有"/"时,采用NoDelimiter能获得21个文件且没有截断路径,采用FolderDelimiter能获得0个文件,但是截断了一个路径(path59/path33/path43/
)。
总结
对象存储的delimiter可以开启文件夹模式来模拟一般操作系统中的文件夹,总体来说还是比较有用的。
平时不看评论,如果希望和我交流可以发邮件到wtysos11@gmail.com。