Go语言之对象存储文件对比更新


前言

对于对象存储自动化管理,文件更新工具 已经描述了在windows上自动对比更新,即检测本地和对象存储的文件列表,选择被改动或者增加的文件进行上传,但未能达到自动化管理(定时检测);以及阿里云效能够实现的把仓库文件推送到OSS的功能也存在问题(未对文件进行对比,上传多余文件),因此制作该程序可实现文件同步功能。

(1)获取阿里云OSS文件列表

func ossFileList() map[string]string {
    // 创建OSSClient实例。
    client, err := oss.New("http://oss-cn-hongkong.aliyuncs.com", "LTA*****toz", "MIv*****JOT")
    if err != nil {
        HandleError(err)
    }

    // 获取存储空间。
    bucketName := "codepages"
    bucket, err := client.Bucket(bucketName)
    if err != nil {
        HandleError(err)
    }

    // 分页列举所有文件。每页列举100个。
    continueToken := ""
    xcodes := make([]ObjectFile, 0)

    var ossfile map[string]string
    ossfile = make(map[string]string)
    for {
        lsRes, err := bucket.ListObjectsV2(oss.MaxKeys(300), oss.ContinuationToken(continueToken))
        if err != nil {
            HandleError(err)
        }
        xcode0 := make([]ObjectFile, len(lsRes.Objects))
        // 打印列举结果。默认情况下,一次返回100条记录。
        for _, object := range lsRes.Objects {
            // fmt.Println(object.Key, object.Type, object.Size, strings.ToLower(object.ETag), object.LastModified, object.StorageClass)
            ossfile[object.Key] = strings.ToLower(strings.Trim(object.ETag, "\""))
        }
        xcodes = append(xcodes, xcode0...)

        if lsRes.IsTruncated {
            continueToken = lsRes.NextContinuationToken
        } else {
            break
        }
    }
    return ossfile
}

(2)获取本地文件列表

func localFileList(originpath string) map[string]string {
    var localfile map[string]string
    localfile = make(map[string]string)
    filepath.Walk(originpath,
        func(path string, f os.FileInfo, err error) error {
            if f == nil {
                return err
            }
            if f.IsDir() {
                //fmt.Println("dir:", path)
                return nil
            }
            // 忽略.git的目录文件
            if strings.HasPrefix(path, originpath+".git") {
                return nil
            }
            file, inerr := os.Open(path)
            if inerr == nil {
                md5h := md5.New()
                io.Copy(md5h, file)
                md5string := fmt.Sprintf("%x", md5h.Sum([]byte("")))
                localfile[strings.TrimPrefix(path, originpath)] = md5string
            }
            return nil
        })
    return localfile
}

(3)更新文件至阿里云OSS

func ossUploadFile(key string, localfile string) {
    // 创建OSSClient实例。
    client, err := oss.New("http://oss-cn-hongkong.aliyuncs.com", "LTA*****toz", "MIv*****JOT")
    if err != nil {
        HandleError(err)
    }

    // 获取存储空间。
    bucketName := "codepages"
    bucket, err := client.Bucket(bucketName)
    if err != nil {
        HandleError(err)
    }
    // 自定义HTTP头部消息
    options := []oss.Option{
		oss.CacheControl("max-age=864000"),
	}
    // 上传本地文件。
    err = bucket.PutObjectFromFile(key, localfile, options...)
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    fmt.Println("[更新成功]", key)
}

(4)主函数调用

func main() {
    originpath := "/home/wwwroot/linzening/"
    lofile := localFileList(originpath)
    osfile := ossFileList()

    // 遍历本地
    for lfile := range lofile {
        // OSS不存在某个文件
        if _, ok := osfile[lfile]; !ok {
            // 上传文件
            fmt.Println("[上传文件]", lfile)
            ossUploadFile(lfile, originpath+lfile)
        } else if lofile[lfile] != osfile[lfile] {
            // MD5不一致,更新文件
            fmt.Println("[更新文件]", lfile, lofile[lfile], osfile[lfile])
            ossUploadFile(lfile, originpath+lfile)
        } else {
            // 文件一致,不处理
            // fmt.Println("[文件正常]", lfile)
        }
    }
}

(5)程序实现

(6)日志记录

由于使用定时器执行程序,要把日志输出到文件中,方便后续查询日志。

logFile, err := os.OpenFile("./oss-update.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
    fmt.Println("open log file failed, err:", err)
    return
}
log.SetOutput(logFile)
log.Println("开始执行【" + ossBucket + "】")

(7)定时器执行

执行git代码同步本机后再执行本机同步到OSS

23 3 * * * cd /home/wwwroot/linzening/ && git pull && cd /home/wwwroot/staticfile/ && git pull && cd /data/cron/ && /data/cron/codepages && /data/cron/template-static-file

打开文件/data/cron/oss-update.log即可查询之前的执行日志。

源代码

https://github.com/linzening/code/blob/main/go/oss-update.go