如何使用騰訊云go sdk 查詢(xún)對(duì)象存儲(chǔ)中最新文件
背景:
騰訊云賬號(hào)下,有很多對(duì)象存儲(chǔ)COS桶:
我現(xiàn)在想確認(rèn)某一個(gè)對(duì)象存儲(chǔ)桶的活躍程度,簡(jiǎn)單的來(lái)說(shuō)。我想知道這個(gè)桶里面最后上傳的一個(gè)文件是什么,以及它的上傳時(shí)間戳。
本文將介紹如何使用騰訊云對(duì)象存儲(chǔ)(COS)的 Go 語(yǔ)言 SDK 查詢(xún)指定存儲(chǔ)桶中的最新文件信息,包括文件路徑和上傳時(shí)間。本教程假設(shè)讀者已經(jīng)具備基本的 Go 語(yǔ)言編程知識(shí),并且對(duì)騰訊云 COS 有一定的了解。
使用騰訊云go sdk 查詢(xún)對(duì)象存儲(chǔ)中最新文件
前置條件
- 您需要擁有一個(gè)騰訊云賬號(hào),并創(chuàng)建了至少一個(gè)COS存儲(chǔ)桶。
- 了解Go語(yǔ)言和基本的并發(fā)編程知識(shí)。
- 確保您已安裝Go運(yùn)行時(shí)環(huán)境。
安裝騰訊云COS Go SDK
在開(kāi)始之前,先確保您的開(kāi)發(fā)環(huán)境已安裝了騰訊云COS的Go SDK。如果尚未安裝,可以使用以下Go命令安裝:
mkdir xxxx go mod int xxxx go get github.com/tencentyun/cos-go-sdk-v5
我們這里的操作是屬于List Object 參照:GetBucket
第一版代碼:
使用chatgpt生成第一版代碼:
main.go
package main import ( "context" "fmt" "net/http" "net/url" "sort" "time" "github.com/tencentyun/cos-go-sdk-v5" ) // 請(qǐng)?zhí)鎿Q下面的假設(shè)值為實(shí)際的 SecretId、SecretKey、BucketName 和 Region。 const ( SecretId = "xxxxxx" SecretKey = "xxxx" BucketName = "xxxxxx" // 例如 "example-1250000000" BucketRegion = "ap-shanghai" // 例如 "ap-guangzhou" ) func main() { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", BucketName, BucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: SecretId, SecretKey: SecretKey, }, }) c := context.Background() opt := &cos.BucketGetOptions{ MaxKeys: 1000, // 修改這個(gè)值以獲取更多或更少的對(duì)象 } v, _, err := client.Bucket.Get(c, opt) if err != nil { panic(err) } // 對(duì)結(jié)果進(jìn)行排序,找到最后更新的對(duì)象 if len(v.Contents) > 0 { sort.Slice(v.Contents, func(i, j int) bool { ti, _ := time.Parse(time.RFC3339, v.Contents[i].LastModified) tj, _ := time.Parse(time.RFC3339, v.Contents[j].LastModified) return ti.After(tj) }) lastUpdatedObj := v.Contents[0] fmt.Printf("最新上傳文件路徑: %s\n", lastUpdatedObj.Key) fmt.Printf("最新上傳時(shí)間: %s\n", lastUpdatedObj.LastModified) } else { fmt.Println("桶中沒(méi)有文件。") } }
運(yùn)行main.go
go run main.go
運(yùn)行后也許感覺(jué)是正確的,畢竟沒(méi)有報(bào)錯(cuò)。但是這里是有問(wèn)題的,為什么呢?因?yàn)槲冶旧聿恢雷詈笠粋€(gè)文件是什么,我手動(dòng)上傳了一個(gè)文件,最后一個(gè)文件應(yīng)該是輸出:go1.22.0.linux-amd64.tar.gz!
什么原因呢?問(wèn)題應(yīng)該是在這里:
c := context.Background() opt := &cos.BucketGetOptions{ MaxKeys: 1000, // 修改這個(gè)值以獲取更多或更少的對(duì)象 }
marker標(biāo)記參數(shù)沒(méi)有設(shè)置
繼續(xù)修改完善main.go代碼:
package main import ( "context" "fmt" "net/http" "net/url" "sort" "time" "github.com/tencentyun/cos-go-sdk-v5" ) // 請(qǐng)?zhí)鎿Q以下的假設(shè)值為實(shí)際的 SecretId、SecretKey、BucketName 和 Region。 const ( SecretId = "xxxxxx" SecretKey = "xxxx" BucketName = "xxxxxx" // 例如 "example-1250000000" BucketRegion = "ap-shanghai" // 例如 "ap-guangzhou" ) func main() { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", BucketName, BucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: SecretId, SecretKey: SecretKey, }, }) c := context.Background() var lastUpdatedObj *cos.Object isTruncated := true nextMarker := "" for isTruncated { opt := &cos.BucketGetOptions{ Marker: nextMarker, MaxKeys: 1000, // 單次請(qǐng)求返回的最大對(duì)象數(shù) } v, _, err := client.Bucket.Get(c, opt) if err != nil { panic(err) } for _, object := range v.Contents { if lastUpdatedObj == nil || object.LastModified > lastUpdatedObj.LastModified { lastUpdatedObj = &object } } // 更新下一個(gè)標(biāo)記和是否截?cái)嗟臉?biāo)志 isTruncated = v.IsTruncated nextMarker = v.NextMarker } // 檢查是否有對(duì)象被找到 if lastUpdatedObj != nil { fmt.Printf("最新上傳文件路徑: %s\n", lastUpdatedObj.Key) fmt.Printf("最新上傳時(shí)間: %s\n", lastUpdatedObj.LastModified) } else { fmt.Println("桶中沒(méi)有文件。") } }
運(yùn)行修改后的main.go文件:
go run main.go
輸出go1.22.0.linux-amd64.tar.gz這個(gè)起碼是正確的!
拆分代碼
想繼續(xù)拆分一下,將客戶(hù)端的創(chuàng)建和查找邏輯拆分到兩個(gè)獨(dú)立的函數(shù)createCOSClient getLastUpdatedFileInfo,然后main函數(shù)中調(diào)用:
package main import ( "context" "fmt" "github.com/tencentyun/cos-go-sdk-v5" "net/http" "net/url" "sort" "time" ) // 請(qǐng)?zhí)鎿Q下面的假設(shè)值為實(shí)際的 SecretId、SecretKey、BucketName 和 Region。 const ( SecretId = "xxxxxx" SecretKey = "xxx" BucketName = "xxxxx" // 例如 "example-1250000000" BucketRegion = "ap-shanghai" // 例如 "ap-guangzhou" ) // 創(chuàng)建 COS 客戶(hù)端 func createCOSClient(secretId, secretKey, bucketName, bucketRegion string) *cos.Client { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucketName, bucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: secretId, SecretKey: secretKey, }, }) return client } func getLastUpdatedFileInfo(client *cos.Client) (key, lastModifiedTime string, err error) { c := context.Background() // 初始化一個(gè)空字符串,表示從桶的開(kāi)頭獲取文件列表 nextMarker := "" var allContents []cos.Object for { opt := &cos.BucketGetOptions{ MaxKeys: 1000, Marker: nextMarker, } v, _, err := client.Bucket.Get(c, opt) if err != nil { return "", "", err } allContents = append(allContents, v.Contents...) // 如果沒(méi)有更多的文件,則停止循環(huán) if !v.IsTruncated { break } // 更新 nextMarker 為下一頁(yè)的開(kāi)始位置 nextMarker = v.NextMarker } // 對(duì)所有結(jié)果進(jìn)行排序以找到最新更新的對(duì)象 if len(allContents) > 0 { sort.Slice(allContents, func(i, j int) bool { ti, errTi := time.Parse(time.RFC3339, allContents[i].LastModified) tj, errTj := time.Parse(time.RFC3339, allContents[j].LastModified) if errTi != nil || errTj != nil { fmt.Printf("Error parsing time: %v, %v", errTi, errTj) return false } return ti.After(tj) }) lastUpdatedObj := allContents[0] return lastUpdatedObj.Key, lastUpdatedObj.LastModified, nil } else { return "", "", fmt.Errorf("桶中沒(méi)有文件") } } func main() { client := createCOSClient(SecretId, SecretKey, BucketName, BucketRegion) key, lastModifiedTime, err := getLastUpdatedFileInfo(client) if err != nil { fmt.Printf("\n查詢(xún)失敗: %v\n", err) return } fmt.Printf("\n最后更新的文件:\n") fmt.Printf("文件路徑: %s\n", key) fmt.Printf("最后修改時(shí)間: %s\n", lastModifiedTime) }
運(yùn)行main.go
go run main.go
注:為了驗(yàn)證代碼有效性,我這里后面又加了一個(gè)新的文件:zaZTYa1i2x.txt
加個(gè)進(jìn)度條
上面的代碼已經(jīng)可以正常滿(mǎn)足需求了,但是我新加一個(gè)進(jìn)度條,顯示查詢(xún)了多少文件了。也能大概知道一個(gè)進(jìn)度的狀況,繼續(xù)修改一下main.go
package main import ( "context" "fmt" "github.com/tencentyun/cos-go-sdk-v5" "net/http" "net/url" "sort" "time" ) // 請(qǐng)?zhí)鎿Q下面的假設(shè)值為實(shí)際的 SecretId、SecretKey、BucketName 和 Region。 const ( SecretId = "xxxx" SecretKey = "xxxxx" BucketName = "xxxxx" // 例如 "example-1250000000" BucketRegion = "ap-shanghai" // 例如 "ap-guangzhou" ) // 創(chuàng)建 COS 客戶(hù)端 func createCOSClient(secretId, secretKey, bucketName, bucketRegion string) *cos.Client { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucketName, bucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: secretId, SecretKey: secretKey, }, }) return client } func getLastUpdatedFileInfo(client *cos.Client) (key, lastModifiedTime string, err error) { c := context.Background() nextMarker := "" var allContents []cos.Object var retrievedCount int fmt.Println("開(kāi)始檢索文件列表...") for { opt := &cos.BucketGetOptions{ MaxKeys: 10000, Marker: nextMarker, } v, _, err := client.Bucket.Get(c, opt) if err != nil { return "", "", err } retrievedCount += len(v.Contents) fmt.Printf("已檢索 %d 個(gè)文件...\r", retrievedCount) // 輸出進(jìn)度信息 '\r' 會(huì)覆蓋當(dāng)前行,這樣我們就可以在同一行更新進(jìn)度 allContents = append(allContents, v.Contents...) if !v.IsTruncated { break } nextMarker = v.NextMarker } fmt.Println("\n文件列表檢索完成。") if len(allContents) > 0 { sort.Slice(allContents, func(i, j int) bool { ti, errTi := time.Parse(time.RFC3339, allContents[i].LastModified) tj, errTj := time.Parse(time.RFC3339, allContents[j].LastModified) if errTi != nil || errTj != nil { fmt.Printf("Error parsing time: %v, %v", errTi, errTj) return false } return ti.After(tj) }) lastUpdatedObj := allContents[0] return lastUpdatedObj.Key, lastUpdatedObj.LastModified, nil } else { return "", "", fmt.Errorf("桶中沒(méi)有文件") } } func main() { client := createCOSClient(SecretId, SecretKey, BucketName, BucketRegion) key, lastModifiedTime, err := getLastUpdatedFileInfo(client) if err != nil { fmt.Printf("\n查詢(xún)失敗: %v\n", err) return } fmt.Printf("\n最后更新的文件:\n") fmt.Printf("文件路徑: %s\n", key) fmt.Printf("最后修改時(shí)間: %s\n", lastModifiedTime) }
運(yùn)行main.go
go run main.go
繼續(xù)完善
繼續(xù)完善一下代碼:我需要把MaxKeys 提取出來(lái),增加一下輸出程序的運(yùn)行時(shí)間,并把輸出文件的時(shí)間戳調(diào)整為東八區(qū)時(shí)間:
package main import ( "context" "fmt" "github.com/tencentyun/cos-go-sdk-v5" "net/http" "net/url" "sort" "time" ) const ( SecretId = "xxxx" SecretKey = "xxxxx" BucketName = "xxxxx" BucketRegion = "ap-shanghai" MaxKeys = 1000 // 設(shè)置最大檢索數(shù)量的常量 ) var cstZone = time.FixedZone("CST", 8*3600) // 東八區(qū)時(shí)區(qū) func createCOSClient(secretId, secretKey, bucketName, bucketRegion string) *cos.Client { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucketName, bucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: secretId, SecretKey: secretKey, }, }) return client } func getLastUpdatedFileInfo(client *cos.Client) (key, lastModifiedTime string, err error) { c := context.Background() nextMarker := "" var allContents []cos.Object var retrievedCount int fmt.Println("開(kāi)始檢索文件列表...") for { opt := &cos.BucketGetOptions{ MaxKeys: MaxKeys, // 使用常量 MaxKeys Marker: nextMarker, } v, _, err := client.Bucket.Get(c, opt) if err != nil { return "", "", err } retrievedCount += len(v.Contents) fmt.Printf("已檢索 %d 個(gè)文件...\r", retrievedCount) allContents = append(allContents, v.Contents...) if !v.IsTruncated { break } nextMarker = v.NextMarker } fmt.Println("\n文件列表檢索完成。") if len(allContents) > 0 { sort.Slice(allContents, func(i, j int) bool { ti, errTi := time.Parse(time.RFC3339, allContents[i].LastModified) tj, errTj := time.Parse(time.RFC3339, allContents[j].LastModified) if errTi != nil || errTj != nil { fmt.Printf("Error parsing time: %v, %v", errTi, errTj) return false } return ti.After(tj) }) lastUpdatedObj := allContents[0] // 將文件的 LastModified 時(shí)間字符串轉(zhuǎn)換為 time.Time t, err := time.Parse(time.RFC3339, lastUpdatedObj.LastModified) if err != nil { return "", "", fmt.Errorf("無(wú)法解析最后修改時(shí)間: %v", err) } // 轉(zhuǎn)換為東八區(qū)時(shí)間 cstTime := t.In(cstZone).Format(time.RFC3339) return lastUpdatedObj.Key, cstTime, nil } else { return "", "", fmt.Errorf("桶中沒(méi)有文件") } } func main() { start := time.Now() // 程序開(kāi)始時(shí)間 client := createCOSClient(SecretId, SecretKey, BucketName, BucketRegion) key, lastModifiedTime, err := getLastUpdatedFileInfo(client) if err != nil { fmt.Printf("\n查詢(xún)失敗: %v\n", err) return } fmt.Printf("\n最后更新的文件:\n") fmt.Printf("文件路徑: %s\n", key) fmt.Printf("最后修改時(shí)間: %s\n", lastModifiedTime) elapsed := time.Since(start) // 程序執(zhí)行時(shí)間 fmt.Printf("\n程序運(yùn)行時(shí)間: %s\n", elapsed) }
運(yùn)行修改后的main.go文件:
go run main.go
繼續(xù)發(fā)散
繼續(xù)發(fā)散一下,我需要輸出最后上傳的10個(gè)文件
package main import ( "context" "fmt" "github.com/tencentyun/cos-go-sdk-v5" "net/http" "net/url" "sort" "time" ) // 請(qǐng)?zhí)鎿Q下面的假設(shè)值為實(shí)際的 SecretId、SecretKey、BucketName 和 Region。 const ( SecretId = "AKID7Mhwz45A9zqcCf4s07A7FIKKTlAiEf7M" SecretKey = "KXbXL0unr2EaBsicYejj1GkEjO2jWOAg" BucketName = "layabox-10028350" // 例如 "example-1250000000" BucketRegion = "ap-shanghai" // 例如 "ap-guangzhou" MaxKeys = 1000 // 設(shè)置最大檢索數(shù)量的常量 NumberOfFiles = 10 // 需要獲取的最后更新的文件數(shù)量 ) var cstZone = time.FixedZone("CST", 8*3600) // 東八區(qū)時(shí)區(qū) func createCOSClient(secretId, secretKey, bucketName, bucketRegion string) *cos.Client { u, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", bucketName, bucketRegion)) b := &cos.BaseURL{BucketURL: u} client := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ SecretID: secretId, SecretKey: secretKey, }, }) return client } func getLastUpdatedFileInfo(client *cos.Client, numberOfFiles int) ([]cos.Object, error) { c := context.Background() nextMarker := "" var allContents []cos.Object var retrievedCount int fmt.Println("開(kāi)始檢索文件列表...") for { opt := &cos.BucketGetOptions{ MaxKeys: MaxKeys, // 使用常量 MaxKeys Marker: nextMarker, } v, _, err := client.Bucket.Get(c, opt) if err != nil { return nil, err } retrievedCount += len(v.Contents) fmt.Printf("已檢索 %d 個(gè)文件...\r", retrievedCount) allContents = append(allContents, v.Contents...) if !v.IsTruncated { break } nextMarker = v.NextMarker } fmt.Println("\n文件列表檢索完成。") fmt.Printf("\n桶中總文件數(shù): %d\n", len(allContents)) if len(allContents) > 0 { sort.Slice(allContents, func(i, j int) bool { ti, errTi := time.Parse(time.RFC3339, allContents[i].LastModified) tj, errTj := time.Parse(time.RFC3339, allContents[j].LastModified) if errTi != nil || errTj != nil { fmt.Printf("Error parsing time: %v, %v", errTi, errTj) return false } return ti.After(tj) }) // 截取切片以獲取最后更新的numberOfFiles個(gè)文件 if len(allContents) > numberOfFiles { allContents = allContents[:numberOfFiles] } // 返回最后更新的numberOfFiles個(gè)文件 return allContents, nil } else { return nil, fmt.Errorf("桶中沒(méi)有文件") } } func main() { start := time.Now() // 程序開(kāi)始時(shí)間 client := createCOSClient(SecretId, SecretKey, BucketName, BucketRegion) files, err := getLastUpdatedFileInfo(client, NumberOfFiles) if err != nil { fmt.Printf("\n查詢(xún)失敗: %v\n", err) return } fmt.Printf("\n最后更新的%d個(gè)文件:\n", NumberOfFiles) for _, file := range files { t, err := time.Parse(time.RFC3339, file.LastModified) if err != nil { fmt.Printf("無(wú)法解析文件 %s 的最后修改時(shí)間: %v\n", file.Key, err) continue } cstTime := t.In(cstZone).Format(time.RFC3339) fmt.Printf("文件路徑: %s\n", file.Key) fmt.Printf("最后修改時(shí)間: %s\n", cstTime) } elapsed := time.Since(start) // 程序執(zhí)行時(shí)間 fmt.Printf("\n程序運(yùn)行時(shí)間: %s\n", elapsed) }
其實(shí)也想過(guò)協(xié)程或者其他方式?但是奈何max-keys 最大是1000測(cè)試了一下沒(méi)有太大的提升放棄了…
總結(jié)
在這篇博客中,我們學(xué)習(xí)了如何使用騰訊云 COS Go SDK 查詢(xún)存儲(chǔ)桶中最新的文件信息。這包括如何創(chuàng)建COS客戶(hù)端,如何逐頁(yè)檢索對(duì)象列表,并如何對(duì)結(jié)果排序以找到最后更新的對(duì)象。我們還展示了如何優(yōu)化用戶(hù)體驗(yàn),通過(guò)實(shí)時(shí)進(jìn)度更新和檢索多個(gè)文件來(lái)改進(jìn)程序。
希望本文能幫助你在使用騰訊云 COS 時(shí)實(shí)現(xiàn)更高效的數(shù)據(jù)管理。
到此這篇關(guān)于使用騰訊云go sdk 查詢(xún)對(duì)象存儲(chǔ)中最新文件的文章就介紹到這了,更多相關(guān)騰訊云go sdk 查詢(xún)對(duì)象存儲(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GO語(yǔ)言gin框架實(shí)現(xiàn)管理員認(rèn)證登陸接口
這篇文章主要介紹了GO語(yǔ)言gin框架實(shí)現(xiàn)管理員認(rèn)證登陸接口,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10go語(yǔ)言中反射機(jī)制的三種使用場(chǎng)景
本文主要介紹了go語(yǔ)言中反射機(jī)制的三種使用場(chǎng)景,包括JSON解析、ORM框架和接口適配,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02Go調(diào)度器學(xué)習(xí)之系統(tǒng)調(diào)用詳解
這篇文章腫,將以一個(gè)簡(jiǎn)單的文件打開(kāi)的系統(tǒng)調(diào)用,來(lái)分析一下Go調(diào)度器在系統(tǒng)調(diào)用時(shí)做了什么。文中的示例代碼講解詳細(xì),需要的可以參考一下2023-04-04Go語(yǔ)言做爬蟲(chóng)狀態(tài)碼返回418的問(wèn)題解決
在使用Go語(yǔ)言做爬蟲(chóng)時(shí),使用http.Get(url)去獲取網(wǎng)頁(yè)內(nèi)容,狀態(tài)碼返回404,本文我們就詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2021-12-12GO語(yǔ)言文件的創(chuàng)建與打開(kāi)實(shí)例分析
這篇文章主要介紹了GO語(yǔ)言文件的創(chuàng)建與打開(kāi)的具體用法,實(shí)例分析了GO語(yǔ)言文件創(chuàng)建與打開(kāi)操作中所涉及的函數(shù)具體用法,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2014-12-12go語(yǔ)言的工作空間和GOPATH環(huán)境變量介紹
這篇文章主要介紹了go語(yǔ)言的工作空間和GOPATH環(huán)境變量介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Golang學(xué)習(xí)之無(wú)類(lèi)型常量詳解
對(duì)于無(wú)類(lèi)型常量,可能大家是第一次聽(tīng)說(shuō),但我們每天都在用,每天都有無(wú)數(shù)潛在的坑被埋下。本文就來(lái)和大家聊聊它的相關(guān)注意事項(xiàng)吧,希望對(duì)大家有所幫助2023-03-03