全部产品
Search
文档中心

Object Storage Service:Unduhan Sederhana (Go SDK V2)

更新时间:Nov 09, 2025

Topik ini menjelaskan cara menggunakan metode unduhan sederhana untuk mengunduh objek dari bucket Object Storage Service (OSS) ke file lokal. Metode ini mudah digunakan dan cocok untuk mengunduh objek dengan cepat.

Catatan Penggunaan

  • Kode contoh dalam topik ini menggunakan ID wilayah cn-hangzhou untuk Wilayah Hangzhou, Tiongkok. Secara default, titik akhir publik digunakan untuk mengakses sumber daya di bucket. Jika Anda ingin mengakses sumber daya di bucket dari layanan Alibaba Cloud lainnya di wilayah yang sama dengan bucket tersebut, gunakan titik akhir internal. Untuk informasi lebih lanjut tentang wilayah dan titik akhir OSS, lihat Wilayah dan Titik Akhir.

  • Dalam topik ini, kredensial akses diambil dari variabel lingkungan. Untuk informasi lebih lanjut tentang cara mengonfigurasi kredensial akses, lihat Konfigurasikan Kredensial Akses.

Izin

Secara default, akun Alibaba Cloud memiliki izin penuh. Pengguna RAM atau Peran RAM di bawah akun Alibaba Cloud tidak memiliki izin apa pun secara default. Akun Alibaba Cloud atau administrator akun harus memberikan izin operasi melalui Kebijakan RAM atau Kebijakan Bucket.

API

Aksi

Definisi

GetObject

oss:GetObject

Mengunduh sebuah objek.

oss:GetObjectVersion

Saat mengunduh objek, jika Anda menentukan versi objek melalui versionId, izin ini diperlukan.

kms:Decrypt

Saat mengunduh objek, jika metadata objek berisi X-Oss-Server-Side-Encryption: KMS, izin ini diperlukan.

Definisi Metode

func (c *Client) GetObject(ctx context.Context, request *GetObjectRequest, optFns ...func(*Options)) (*GetObjectResult, error)

Parameter Permintaan

Parameter

Tipe

Deskripsi

ctx

context.Context

Konteks permintaan. Anda dapat menggunakan parameter ini untuk menentukan batas waktu total untuk permintaan.

request

*GetObjectRequest

Parameter permintaan untuk operasi API tertentu. Untuk informasi lebih lanjut, lihat GetObjectRequest.

optFns

...func(*Options)

(Opsional) Parameter konfigurasi tingkat operasi. Untuk informasi lebih lanjut, lihat Options.

Nilai Kembali

Nilai Kembali

Tipe

Deskripsi

result

*GetObjectResult

Nilai kembali dari operasi API. Parameter ini hanya valid jika err adalah nil. Untuk informasi lebih lanjut, lihat GetObjectResult.

err

error

Status permintaan. Jika permintaan gagal, nilai err tidak akan menjadi nil.

Kode Contoh

Berikut adalah kode contoh yang menunjukkan cara mengunduh objek dari bucket ke file lokal.

package main

import (
	"context"
	"flag"
	"io"
	"log"
	"os"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah tempat bucket berada.
	bucketName string // Nama bucket.
	objectName string // Nama objek.
)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&objectName, "object", "", "Nama objek.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Periksa apakah nama bucket kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek diperlukan")
	}

	// Tentukan jalur file keluaran.
	outputFile := "downloaded.file" // Ganti string ini dengan jalur tempat Anda ingin menyimpan file.

	// Muat konfigurasi default dan tentukan penyedia kredensial serta wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Buat permintaan untuk meminta objek.
	request := &oss.GetObjectRequest{
		Bucket: oss.Ptr(bucketName), // Nama bucket.
		Key:    oss.Ptr(objectName), // Nama objek.
	}

	// Minta objek dan proses hasilnya.
	result, err := client.GetObject(context.TODO(), request)
	if err != nil {
		log.Fatalf("gagal mendapatkan objek %v", err)
	}
	defer result.Body.Close() // Pastikan badan respons ditutup saat fungsi berakhir.

	// Baca seluruh konten file sekaligus.
	data, err := io.ReadAll(result.Body)
	if err != nil {
		log.Fatalf("gagal membaca objek %v", err)
	}

	// Tulis konten ke file.
	err = os.WriteFile(outputFile, data, 0644)
	if err != nil {
		log.Fatalf("gagal menulis ke file keluaran %v", err)
	}

	log.Printf("file berhasil diunduh ke %s", outputFile)
}

Skenario

Unduhan Bersyarat

Saat Anda mengunduh objek, Anda dapat menentukan kondisi berdasarkan waktu terakhir dimodifikasi atau ETag-nya. Objek hanya akan diunduh jika kondisi yang ditentukan terpenuhi. Jika tidak, kesalahan akan dikembalikan. Unduhan bersyarat mengurangi lalu lintas jaringan dan konsumsi sumber daya yang tidak perlu, sehingga meningkatkan efisiensi unduhan.

Tabel berikut menjelaskan kondisi yang didukung oleh OSS.

Catatan
  • Kondisi If-Modified-Since dan If-Unmodified-Since dapat digunakan bersama-sama. Kondisi If-Match dan If-None-Match juga dapat digunakan bersama-sama.

  • Anda dapat memanggil metode ossClient.getObjectMeta untuk mengambil ETag objek.

Parameter

Deskripsi

IfModifiedSince

Jika waktu yang ditentukan lebih awal daripada waktu terakhir kali objek dimodifikasi, objek dapat diunduh. Jika tidak, 304 Not modified akan dikembalikan.

IfUnmodifiedSince

Jika waktu yang ditentukan lebih lambat atau sama dengan waktu terakhir kali objek dimodifikasi, objek dapat diunduh. Jika tidak, 412 Precondition failed akan dikembalikan.

IfMatch

Jika ETag yang ditentukan cocok dengan ETag objek, objek dapat diunduh. Jika tidak, 412 Precondition failed akan dikembalikan.

IfNoneMatch

Jika ETag yang ditentukan tidak cocok dengan ETag objek, objek dapat diunduh. Jika tidak, 304 Not modified akan dikembalikan.

Berikut adalah kode contoh yang menunjukkan cara melakukan unduhan bersyarat.

package main

import (
	"context"
	"flag"
	"log"
	"net/http"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah tempat bucket berada.
	bucketName string // Nama bucket.
	objectName string // Nama objek.
)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&objectName, "object", "", "Nama objek.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Periksa apakah nama bucket kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek diperlukan")
	}

	// Muat konfigurasi default dan tentukan penyedia kredensial serta wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Tentukan jalur file lokal.
	localFile := "download.file"

	// Anggaplah bahwa objek terakhir dimodifikasi pada pukul 18:43:02 tanggal 21 Oktober 2024. Jika waktu UTC yang Anda masukkan lebih awal dari waktu ini, kondisi IfModifiedSince terpenuhi dan unduhan dipicu.
	date := time.Date(2024, time.October, 21, 18, 43, 2, 0, time.UTC)

	// Anggaplah bahwa ETag adalah "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855". Jika ETag yang Anda masukkan sama dengan ETag objek, kondisi IfMatch terpenuhi dan unduhan dipicu.
	etag := "\"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\""

	// Buat permintaan untuk mengunduh objek ke file lokal.
	getRequest := &oss.GetObjectRequest{
		Bucket:          oss.Ptr(bucketName),                   // Nama bucket.
		Key:             oss.Ptr(objectName),                   // Nama objek.
		IfModifiedSince: oss.Ptr(date.Format(http.TimeFormat)), // Tentukan parameter IfModifiedSince.
		IfMatch:         oss.Ptr(etag),                         // Tentukan parameter IfMatch.
	}

	// Unduh objek ke file lokal dan proses hasilnya.
	result, err := client.GetObjectToFile(context.TODO(), getRequest, localFile)
	if err != nil {
		log.Fatalf("gagal mendapatkan objek ke file %v", err)
	}

	log.Printf("hasil objek ke file:%#v\n", result)
}

Tampilkan Bilah Kemajuan untuk Unduhan File

Saat mengunduh file, Anda dapat menggunakan bilah kemajuan untuk memantau kemajuan unduhan secara real-time. Ini berguna untuk melacak status unduhan file besar.

Berikut adalah kode contoh yang menunjukkan cara menampilkan bilah kemajuan untuk unduhan file.

package main

import (
	"context"
	"flag"
	"fmt"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah tempat bucket berada.
	bucketName string // Nama bucket.
	objectName string // Nama objek.
)

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&objectName, "object", "", "Nama objek.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Periksa apakah nama bucket kosong.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	// Periksa apakah wilayah kosong.
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Periksa apakah nama objek kosong.
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama objek diperlukan")
	}

	// Muat konfigurasi default dan tentukan penyedia kredensial serta wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	// Tentukan jalur file lokal.
	localFile := "download.file"

	// Buat permintaan untuk mengunduh objek ke file lokal.
	getRequest := &oss.GetObjectRequest{
		Bucket: oss.Ptr(bucketName), // Nama bucket.
		Key:    oss.Ptr(objectName), // Nama objek.
		ProgressFn: func(increment, transferred, total int64) {
			fmt.Printf("increment:%v, transferred:%v, total:%v\n", increment, transferred, total)
		}, // Fungsi callback untuk kemajuan, yang menampilkan kemajuan unduhan.
	}

	// Unduh objek ke file lokal dan proses hasilnya.
	result, err := client.GetObjectToFile(context.TODO(), getRequest, localFile)
	if err != nil {
		log.Fatalf("gagal mendapatkan objek ke file %v", err)
	}

	log.Printf("hasil objek ke file:%#v\n", result)
}

Unduhan Batch File ke Perangkat Lokal

package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// Tentukan variabel global.
var (
	region     string // Wilayah tempat bucket berada.
	bucketName string // Nama bucket.
	prefix     string // Awalan objek (jalur folder).
	localDir   string // Direktori unduhan lokal.
	maxWorkers int    // Konkurensi maksimum.
	maxKeys    int    // Jumlah maksimum objek yang terdaftar sekaligus.
)

// DownloadTask: struktur tugas unduhan.
type DownloadTask struct {
	ObjectKey string
	LocalPath string
	Size      int64
}

// DownloadResult: struktur hasil unduhan.
type DownloadResult struct {
	ObjectKey string
	Success   bool
	Error     error
	Size      int64
}

// Fungsi init digunakan untuk menginisialisasi parameter baris perintah.
func init() {
	flag.StringVar(&region, "region", "", "Wilayah tempat bucket berada.")
	flag.StringVar(&bucketName, "bucket", "", "Nama bucket.")
	flag.StringVar(&prefix, "prefix", "", "Awalan (jalur folder) untuk diunduh.")
	flag.StringVar(&localDir, "local-dir", "./downloads", "Direktori lokal untuk menyimpan file yang diunduh.")
	flag.IntVar(&maxWorkers, "workers", 5, "Jumlah maksimum unduhan konkuren.")
	flag.IntVar(&maxKeys, "max-keys", 1000, "Jumlah maksimum objek yang terdaftar sekaligus.")
}

func main() {
	// Parsing parameter baris perintah.
	flag.Parse()

	// Periksa parameter yang diperlukan.
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, nama bucket diperlukan")
	}

	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("parameter tidak valid, wilayah diperlukan")
	}

	// Pastikan bahwa awalan diakhiri dengan garis miring (/) jika bukan string kosong.
	if prefix != "" && !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	// Buat direktori unduhan lokal.
	if err := os.MkdirAll(localDir, 0755); err != nil {
		log.Fatalf("gagal membuat direktori lokal: %v", err)
	}

	// Muat konfigurasi default dan tentukan penyedia kredensial serta wilayah.
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// Buat klien OSS.
	client := oss.NewClient(cfg)

	fmt.Printf("Mulai unduhan batch. Bucket: %s, Awalan: %s, Direktori lokal: %s\n", bucketName, prefix, localDir)

	// Daftarkan semua objek yang akan diunduh.
	tasks, err := listObjects(client, bucketName, prefix)
	if err != nil {
		log.Fatalf("gagal mendaftarkan objek: %v", err)
	}

	if len(tasks) == 0 {
		fmt.Println("Tidak ada file yang ditemukan untuk diunduh.")
		return
	}

	fmt.Printf("Ditemukan %d file untuk diunduh\n", len(tasks))

	// Lakukan unduhan batch.
	results := batchDownload(client, tasks, maxWorkers)

	// Hitung hasil unduhan.
	var successCount, failCount int
	var totalSize int64
	for _, result := range results {
		if result.Success {
			successCount++
			totalSize += result.Size
		} else {
			failCount++
			fmt.Printf("Unduhan gagal: %s, Kesalahan: %v\n", result.ObjectKey, result.Error)
		}
	}

	fmt.Printf("\nUnduhan selesai! Berhasil: %d, Gagal: %d, Total ukuran: %s\n",
		successCount, failCount, formatBytes(totalSize))
}

// listObjects mencantumkan semua objek yang memiliki awalan tertentu di bucket.
func listObjects(client *oss.Client, bucketName, prefix string) ([]DownloadTask, error) {
	var tasks []DownloadTask
	var continuationToken *string

	for {
		// Buat permintaan untuk mendaftarkan objek.
		request := &oss.ListObjectsV2Request{
			Bucket:            oss.Ptr(bucketName),
			Prefix:            oss.Ptr(prefix),
			MaxKeys:           int32(maxKeys),
			ContinuationToken: continuationToken,
		}

		// Lakukan operasi pencatatan.
		result, err := client.ListObjectsV2(context.TODO(), request)
		if err != nil {
			return nil, fmt.Errorf("gagal mendaftarkan objek: %w", err)
		}

		// Proses hasil pencatatan.
		for _, obj := range result.Contents {
			// Lewati objek folder yang diakhiri dengan garis miring (/) dan memiliki ukuran 0.
			if strings.HasSuffix(*obj.Key, "/") && obj.Size == 0 {
				continue
			}

			// Hitung jalur file lokal.
			relativePath := strings.TrimPrefix(*obj.Key, prefix)
			localPath := filepath.Join(localDir, relativePath)

			tasks = append(tasks, DownloadTask{
				ObjectKey: *obj.Key,
				LocalPath: localPath,
				Size:      obj.Size,
			})
		}

		// Periksa apakah ada objek lain.
		if result.NextContinuationToken == nil {
			break
		}
		continuationToken = result.NextContinuationToken
	}

	return tasks, nil
}

// batchDownload melakukan unduhan batch.
func batchDownload(client *oss.Client, tasks []DownloadTask, maxWorkers int) []DownloadResult {
	taskChan := make(chan DownloadTask, len(tasks))
	resultChan := make(chan DownloadResult, len(tasks))

	// Mulai korutin pekerja unduhan.
	var wg sync.WaitGroup
	for i := 0; i < maxWorkers; i++ {
		wg.Add(1)
		go downloadWorker(client, bucketName, taskChan, resultChan, &wg)
	}

	// Kirim tugas unduhan.
	go func() {
		for _, task := range tasks {
			taskChan <- task
		}
		close(taskChan)
	}()

	// Tunggu semua korutin pekerja selesai.
	go func() {
		wg.Wait()
		close(resultChan)
	}()

	// Kumpulkan hasil dan tampilkan kemajuan.
	var results []DownloadResult
	completed := 0
	total := len(tasks)

	for result := range resultChan {
		results = append(results, result)
		completed++

		if result.Success {
			fmt.Printf("✓ [%d/%d] %s (%s)\n",
				completed, total, result.ObjectKey, formatBytes(result.Size))
		} else {
			fmt.Printf("✗ [%d/%d] %s - Kesalahan: %v\n",
				completed, total, result.ObjectKey, result.Error)
		}
	}

	return results
}

// downloadWorker: korutin pekerja unduhan.
func downloadWorker(client *oss.Client, bucketName string, taskChan <-chan DownloadTask,
	resultChan chan<- DownloadResult, wg *sync.WaitGroup) {
	defer wg.Done()

	for task := range taskChan {
		result := DownloadResult{
			ObjectKey: task.ObjectKey,
			Size:      task.Size,
		}

		// Buat direktori file lokal.
		if err := os.MkdirAll(filepath.Dir(task.LocalPath), 0755); err != nil {
			result.Error = fmt.Errorf("gagal membuat direktori: %w", err)
			resultChan <- result
			continue
		}

		// Periksa apakah file sudah ada dan memiliki ukuran yang sama.
		if fileInfo, err := os.Stat(task.LocalPath); err == nil {
			if fileInfo.Size() == task.Size {
				result.Success = true
				resultChan <- result
				continue
			}
		}

		// Buat permintaan unduhan.
		getRequest := &oss.GetObjectRequest{
			Bucket: oss.Ptr(bucketName),
			Key:    oss.Ptr(task.ObjectKey),
		}

		// Lakukan unduhan.
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
		_, err := client.GetObjectToFile(ctx, getRequest, task.LocalPath)
		cancel()

		if err != nil {
			result.Error = err
		} else {
			result.Success = true
		}

		resultChan <- result
	}
}

// formatBytes memformat jumlah byte menjadi format yang mudah dibaca manusia.
func formatBytes(bytes int64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}
	div, exp := int64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

Penggunaan

# Kompilasi kode uji menjadi file yang dapat dieksekusi.
go build -o oss-batch-download main.go

# Unduh folder yang ditentukan.
./oss-batch-download -region oss-cn-hangzhou -bucket my-bucket -prefix images/2024/

# Sesuaikan direktori lokal dan konkurensi.
./oss-batch-download -region oss-cn-hangzhou -bucket my-bucket -prefix documents/ -local-dir ./downloads -workers 10

# Unduh seluruh bucket.
./oss-batch-download -region oss-cn-hangzhou -bucket my-bucket -prefix ""

Contoh Keluaran

Saat program berjalan, kemajuan unduhan detail ditampilkan:

Mulai unduhan batch. Bucket: my-bucket, Awalan: images/2024/, Direktori lokal: ./downloads
Ditemukan 150 file untuk diunduh
✓ [1/150] images/2024/photo1.jpg (2.3 MB)
✓ [2/150] images/2024/photo2.png (1.8 MB)
...
Unduhan selesai! Berhasil: 148, Gagal: 2, Total ukuran: 1.2 GB

Referensi

  • Untuk kode contoh lengkap untuk mengunduh objek ke file lokal, lihat contoh GitHub.

  • Untuk informasi lebih lanjut tentang operasi API untuk mengunduh objek ke file lokal, lihat GetObjectToFile dan GetObject.