Go 语言通过执行 mc 命令实现跨账号拷贝的示例代码:
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
)
// MC配置结构
type MCConfig struct {
SourceAlias string
DestinationAlias string
Workers int
}
// 复制任务结构
type CopyTask struct {
SourcePath string
DestinationPath string
}
// 配置mc客户端
func configureMC(sourceEndpoint, sourceAccessKey, sourceSecretKey,
destEndpoint, destAccessKey, destSecretKey string) error {
// 配置源端点
sourceCmd := exec.Command("mc", "alias", "set", "source",
sourceEndpoint, sourceAccessKey, sourceSecretKey)
if err := sourceCmd.Run(); err != nil {
return fmt.Errorf("error configuring source alias: %v", err)
}
// 配置目标端点
destCmd := exec.Command("mc", "alias", "set", "destination",
destEndpoint, destAccessKey, destSecretKey)
if err := destCmd.Run(); err != nil {
return fmt.Errorf("error configuring destination alias: %v", err)
}
return nil
}
// 列出对象
func listObjects(mcAlias, bucket, prefix string) ([]string, error) {
cmd := exec.Command("mc", "ls", "--recursive",
fmt.Sprintf("%s/%s/%s", mcAlias, bucket, prefix))
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("error listing objects: %v", err)
}
var objects []string
scanner := bufio.NewScanner(strings.NewReader(string(output)))
for scanner.Scan() {
line := scanner.Text()
// 解析mc ls的输出,提取对象路径
parts := strings.Fields(line)
if len(parts) >= 4 {
objects = append(objects, parts[len(parts)-1])
}
}
return objects, nil
}
// 复制单个对象
func copyObject(task CopyTask) error {
cmd := exec.Command("mc", "cp", task.SourcePath, task.DestinationPath)
// 获取命令的标准输出和错误输出
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("error copying %s: %v\nOutput: %s",
task.SourcePath, err, string(output))
}
fmt.Printf("Successfully copied: %s\n", task.SourcePath)
return nil
}
// 并行复制对象
func copyObjects(tasks []CopyTask, workers int) error {
var wg sync.WaitGroup
errorsChan := make(chan error, len(tasks))
tasksChan := make(chan CopyTask, len(tasks))
// 启动工作协程
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range tasksChan {
if err := copyObject(task); err != nil {
errorsChan <- err
}
}
}()
}
// 发送任务
for _, task := range tasks {
tasksChan <- task
}
close(tasksChan)
// 等待所有工作完成
wg.Wait()
close(errorsChan)
// 收集错误
var errors []error
for err := range errorsChan {
errors = append(errors, err)
}
if len(errors) > 0 {
return fmt.Errorf("encountered %d errors during copy: %v",
len(errors), errors)
}
return nil
}
func main() {
// MC配置
config := MCConfig{
SourceAlias: "source",
DestinationAlias: "destination",
Workers: 5,
}
// 配置MC客户端
err := configureMC(
"source-endpoint:9000", // 源端点
"source-access-key", // 源访问密钥
"source-secret-key", // 源密钥
"destination-endpoint:9000", // 目标端点
"dest-access-key", // 目标访问密钥
"dest-secret-key", // 目标密钥
)
if err != nil {
log.Fatalf("Error configuring mc: %v", err)
}
// 源和目标桶配置
sourceBucket := "source-bucket"
destBucket := "dest-bucket"
prefix := "some/prefix/"
// 列出所有需要复制的对象
objects, err := listObjects(config.SourceAlias, sourceBucket, prefix)
if err != nil {
log.Fatalf("Error listing objects: %v", err)
}
// 创建复制任务
var tasks []CopyTask
for _, object := range objects {
sourceFullPath := fmt.Sprintf("%s/%s/%s",
config.SourceAlias, sourceBucket, object)
destFullPath := fmt.Sprintf("%s/%s/%s",
config.DestinationAlias, destBucket, object)
tasks = append(tasks, CopyTask{
SourcePath: sourceFullPath,
DestinationPath: destFullPath,
})
}
// 开始复制
fmt.Printf("Starting to copy %d objects with %d workers\n",
len(tasks), config.Workers)
if err := copyObjects(tasks, config.Workers); err != nil {
log.Fatalf("Error during copy: %v", err)
}
fmt.Println("Copy completed successfully")
}
这个实现:
- 使用
exec.Command
执行 mc 命令 - 首先配置源和目标的 mc alias
- 使用
mc ls
命令列出需要复制的对象 - 使用
mc cp
命令执行实际的复制操作 - 支持并行复制多个对象
- 包含错误处理和日志记录
使用前请确保:
- mc 命令行工具已经安装在系统中
- mc 命令可以在系统 PATH 中找到
- 有适当的权限执行 mc 命令
- 源和目标的访问凭证正确
你可以这样使用这个程序:
- 修改配置参数(端点、访问密钥等)
- 设置源桶和目标桶
- 设置要复制的前缀路径
- 运行程序
程序会并行复制对象,并显示进度信息。如果发生错误,会收集并报告这些错误。
要添加更多功能,你可以:
- 添加进度条显示
- 添加重试机制
- 添加详细的日志记录
- 添加断点续传功能
- 添加配置文件支持
希望这个实现对你有帮助!