背景
由于近期考虑使用 COS 做一些数据备份,所以写了这个程序。
直接看效果:
源码
cos/cos.go
package cos
import (
"context"
"encoding/json"
"fmt"
"github.com/tencentyun/cos-go-sdk-v5"
"log"
"net/http"
"net/url"
"os"
"path"
"zze/tencent-cloud-cos/utils"
)
func InitCosConfig() {
config := CosConfig{
BucketUrl: "https://<bucket_name>.cos.ap-guangzhou.myqcloud.com",
ServiceUrl: "https://cos.<region>.myqcloud.com",
SecretId: "<secret_id>",
SecretKey: "<secret_key>",
}
homeDirPath := os.Getenv("HOME")
configFilePath := path.Join(homeDirPath, ".cos/config.json")
utils.WriteStringToFile(utils.MarshalObjToJson(config), configFilePath)
}
func getCosConfig() (*CosConfig, error) {
homeDirPath := os.Getenv("HOME")
configFilePath := path.Join(homeDirPath, ".cos/config.json")
if !utils.FileExist(configFilePath) {
return nil, fmt.Errorf("配置文件 %s 不存在!", configFilePath)
}
configStr := utils.ReadFile(configFilePath)
config := new(CosConfig)
err := json.Unmarshal([]byte(configStr), config)
if err != nil {
return nil, fmt.Errorf("配置文件 %s 内容格式错误!err: %v", configFilePath, err)
}
return config, nil
}
type CosConfig struct {
BucketUrl string `json:"bucket_url"`
ServiceUrl string `json:"service_url"`
SecretId string `json:"secret_id"`
SecretKey string `json:"secret_key"`
}
type CosClient struct {
client *cos.Client
}
func NewCosClient() (*CosClient, error) {
var cosClient = new(CosClient)
config, err := getCosConfig()
if err != nil {
return nil, err
}
u, _ := url.Parse(config.BucketUrl)
su, _ := url.Parse(config.ServiceUrl)
b := &cos.BaseURL{BucketURL: u, ServiceURL: su}
client := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: config.SecretId,
SecretKey: config.SecretKey,
},
})
cosClient.client = client
return cosClient, nil
}
// 上传文件对象到 bucket
func (cosCli CosClient) PutObj(objectKey string, filePath string) {
_, _, err := cosCli.client.Object.Upload(
context.Background(), objectKey, filePath, nil,
)
if err != nil {
log.Fatalf("上传文件 [%s] 到 [%s] 失败!err: %v", filePath, objectKey, err)
}
}
// 从 bucket 删除文件对象
func (cosCli CosClient) DeleteObj(objectKey string) {
_, err := cosCli.client.Object.Delete(context.Background(), objectKey)
if err != nil {
log.Fatalf("删除文件 [%s] 失败!err: %v", objectKey, err)
}
}
// 从 bucket 下载文件对象
func (cosCli CosClient) DownloadObj(objectKey string, savePath string) {
opt := &cos.MultiDownloadOptions{
ThreadPoolSize: 5,
}
_, err := cosCli.client.Object.Download(
context.Background(), objectKey, savePath, opt,
)
if err != nil {
log.Fatalf("下载文件 [%s] 到 [%s] 失败!err: %v", objectKey, savePath, err)
}
}
// 列出 bucket 中的对象
func (cosCli CosClient) ListObj(prefix string, maxKeys int) {
opt := &cos.BucketGetOptions{
Prefix: prefix,
MaxKeys: maxKeys,
}
v, _, err := cosCli.client.Bucket.Get(context.Background(), opt)
if err != nil {
log.Fatalf("查询路径 [%s] 下的对象列表失败!err: %v", prefix, err)
}
for _, content := range v.Contents {
fmt.Printf("%v\n", content.Key)
}
}
utils/file.go
package utils
import (
"bufio"
"bytes"
"encoding/json"
"io/ioutil"
"log"
"os"
)
func FileExist(path string) bool {
_, err := os.Lstat(path)
return !os.IsNotExist(err)
}
func ReadFile(path string) string {
b, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("读取文件 [%s] 失败!", path)
}
return string(b)
}
func WriteStringToFile(msg string, destFilePath string) {
fileHandle, err := os.OpenFile(destFilePath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
log.Fatalf("打开文件 [%s] 失败, err: %v", destFilePath, err)
}
defer func() {
err = fileHandle.Close()
if err != nil {
log.Fatalf("关闭文件 [%s] 失败, err: %v", destFilePath, err)
}
}()
buf := bufio.NewWriterSize(fileHandle, len(msg))
_, err = buf.WriteString(msg)
if err != nil {
log.Fatalf("写入字符串到文件 [%s] 失败, err: %v", err)
}
err = buf.Flush()
if err != nil {
log.Fatalf("刷新缓存到文件 [%s] 失败, err: %v", err)
}
}
func MarshalObjToJson(obj interface{}) string {
bf := bytes.NewBuffer([]byte{})
jsonEncoder := json.NewEncoder(bf)
jsonEncoder.SetEscapeHTML(false)
jsonEncoder.SetIndent(" ", "")
err := jsonEncoder.Encode(obj)
if err != nil {
log.Fatalf("序列化对象 [%v] 失败, err: %v", obj)
}
return bf.String()
}
main.go
package main
import (
"fmt"
"github.com/gookit/gcli"
"log"
"strconv"
"zze/tencent-cloud-cos/cos"
)
var (
client *cos.CosClient
err error
)
func listCmd() *gcli.Command {
cmd := &gcli.Command{
Name: "list",
UseFor: "查询列表",
Aliases: []string{"ls"},
Func: func(cmd *gcli.Command, args []string) int {
prefixArg := cmd.Arg("prefix")
maxKeysArg := cmd.Arg("max_keys")
maxKeys := 100
if maxKeysArg.HasValue() {
num, err := strconv.Atoi(fmt.Sprintf("%s", maxKeysArg.Value))
if err != nil {
log.Fatalf("参数 <max_keys> 必须是整数类型")
}
maxKeys = num
}
client.ListObj(fmt.Sprintf("%s", prefixArg.Value), maxKeys)
return 0
},
}
cmd.AddArg("prefix", "bucket 目录/路径前缀", true)
cmd.AddArg("max_keys", "最大返回记录条数", false)
return cmd
}
func downloadCmd() *gcli.Command {
cmd := &gcli.Command{
Name: "download",
UseFor: "下载对象",
Aliases: []string{"get"},
Func: func(cmd *gcli.Command, args []string) int {
keyPathArg := cmd.Arg("key_path")
savePath := cmd.Arg("save_path")
client.DownloadObj(fmt.Sprintf("%s", keyPathArg.Value), fmt.Sprintf("%s", savePath.Value))
return 0
},
}
cmd.AddArg("key_path", "对象路径", true)
cmd.AddArg("save_path", "保存文件的本地目标路径", true)
return cmd
}
func uploadCmd() *gcli.Command {
cmd := &gcli.Command{
Name: "upload",
UseFor: "上传对象",
Aliases: []string{"put"},
Func: func(cmd *gcli.Command, args []string) int {
keyPathArg := cmd.Arg("key_path")
file_path := cmd.Arg("file_path")
client.PutObj(fmt.Sprintf("%s", keyPathArg.Value), fmt.Sprintf("%s", file_path.Value))
return 0
},
}
cmd.AddArg("key_path", "对象路径", true)
cmd.AddArg("file_path", "本地文件路径", true)
return cmd
}
func main() {
client, err = cos.NewCosClient()
app := gcli.NewApp()
app.Version = "1.0.0"
app.Description = "一个支持快速从腾讯云 bucket 上传、下载或删除文件命令行程序"
// 添加一个自定义的子 Command
app.Add(&gcli.Command{
Name: "init",
UseFor: "初始化配置文件 [$HOME/.cos/config.json]",
Aliases: []string{"i"},
Func: func(cmd *gcli.Command, args []string) int {
cos.InitCosConfig()
return 0
},
})
if err == nil {
app.Add(listCmd())
app.Add(downloadCmd())
app.Add(uploadCmd())
} else {
log.Printf("err: %v", err)
}
app.Run()
}
使用
第一次执行会有提示信息:
$ cosctl
2022/01/20 21:04:34 err: 配置文件 /root/.cos/config.json 不存在!
一个支持快速从腾讯云 bucket 上传、下载或删除文件命令行程序 (Version: 1.0.0)
Usage:
cosctl [Global Options...] {command} [--option ...] [argument ...]
Global Options:
--verbose Set error reporting level(quiet 0 - 4 debug)
--no-color Disable color when outputting message
-h, --help Display the help information
-V, --version Display app version information
Available Commands:
init 初始化配置文件 [$HOME/.cos/config.json] (alias: i)
help Display help information
Use "cosctl {command} -h" for more information about a command
如上提示信息,我们需要创建配置目录,然后执行初始化配置操作:
$ mkdir ~/.cos
$ cosctl init
修改配置:
# bucket_name, cos 存储桶名称
# region, cos 所在区域
# secret_id, api 访问 secret id
# secret_key, api 访问 secret key
$ cat ~/.cos/config.json
{
"bucket_url": "https://<bucket_name>.cos.ap-guangzhou.myqcloud.com",
"service_url": "https://cos.<region>.myqcloud.com",
"secret_id": "<secret_id>",
"secret_key": "<secret_key>"
}
修改好如上配置后就可以对存储桶执行管理操作了:
$ cosctl
一个支持快速从腾讯云 bucket 上传、下载或删除文件命令行程序 (Version: 1.0.0)
Usage:
cosctl [Global Options...] {command} [--option ...] [argument ...]
Global Options:
--verbose Set error reporting level(quiet 0 - 4 debug)
--no-color Disable color when outputting message
-h, --help Display the help information
-V, --version Display app version information
Available Commands:
download 下载对象 (alias: get)
init 初始化配置文件 [$HOME/.cos/config.json] (alias: i)
list 查询列表 (alias: ls)
upload 上传对象 (alias: put)
help Display help information
Use "cosctl {command} -h" for more information about a command
子命令使用帮助可通过 -h
获取:
$ cosctl list -h
查询列表
Name: list (alias: ls)
Usage: cosctl [Global Options...] list [--option ...] [argument ...]
Global Options:
--verbose Set error reporting level(quiet 0 - 4 debug)
--no-color Disable color when outputting message
-h, --help Display this help information
Arguments:
prefix Bucket 目录/路径前缀*
max_keys 最大返回记录条数
$ cosctl upload -h
上传对象
Name: upload (alias: put)
Usage: cosctl [Global Options...] upload [--option ...] [argument ...]
Global Options:
--verbose Set error reporting level(quiet 0 - 4 debug)
--no-color Disable color when outputting message
-h, --help Display this help information
Arguments:
key_path 对象路径*
file_path 本地文件路径*
$ cosctl get -h
下载对象
Name: download (alias: get)
Usage: cosctl [Global Options...] download [--option ...] [argument ...]
Global Options:
--verbose Set error reporting level(quiet 0 - 4 debug)
--no-color Disable color when outputting message
-h, --help Display this help information
Arguments:
key_path 对象路径*
save_path 保存文件的本地目标路径*
下载
我已经编译好 linux 和 mac 下的二进制文件,可通过如下网盘链接获取:
- 链接:https://pan.baidu.com/s/1ORnHMMyuxA5mlA-QlM8Elg
- 提取码:
75s4
当然你如果有足够的动手能力的也可以对上述源码进行定制然后自己编译~
评论区