github.com/aavshr/aws-sdk-go@v1.41.3/example/service/s3/getObjectWithProgress/getObjectWithProgress.go (about)

     1  //go:build example
     2  // +build example
     3  
     4  package main
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"strings"
    13  	"sync/atomic"
    14  
    15  	"github.com/aavshr/aws-sdk-go/aws"
    16  	"github.com/aavshr/aws-sdk-go/aws/session"
    17  	"github.com/aavshr/aws-sdk-go/service/s3"
    18  	"github.com/aavshr/aws-sdk-go/service/s3/s3manager"
    19  )
    20  
    21  // progressWriter tracks the download progress of a file from S3 to a file
    22  // as the writeAt method is called, the byte size is added to the written total,
    23  // and then a log is printed of the written percentage from the total size
    24  // it looks like this on the command line:
    25  //  2019/02/22 12:59:15 File size:35943530 downloaded:16360 percentage:0%
    26  //  2019/02/22 12:59:15 File size:35943530 downloaded:16988 percentage:0%
    27  //  2019/02/22 12:59:15 File size:35943530 downloaded:33348 percentage:0%
    28  type progressWriter struct {
    29  	written int64
    30  	writer  io.WriterAt
    31  	size    int64
    32  }
    33  
    34  func (pw *progressWriter) WriteAt(p []byte, off int64) (int, error) {
    35  	atomic.AddInt64(&pw.written, int64(len(p)))
    36  
    37  	percentageDownloaded := float32(pw.written*100) / float32(pw.size)
    38  
    39  	fmt.Printf("File size:%d downloaded:%d percentage:%.2f%%\r", pw.size, pw.written, percentageDownloaded)
    40  
    41  	return pw.writer.WriteAt(p, off)
    42  }
    43  
    44  func byteCountDecimal(b int64) string {
    45  	const unit = 1000
    46  	if b < unit {
    47  		return fmt.Sprintf("%d B", b)
    48  	}
    49  	div, exp := int64(unit), 0
    50  	for n := b / unit; n >= unit; n /= unit {
    51  		div *= unit
    52  		exp++
    53  	}
    54  	return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
    55  }
    56  
    57  func getFileSize(svc *s3.S3, bucket string, prefix string) (filesize int64, error error) {
    58  	params := &s3.HeadObjectInput{
    59  		Bucket: aws.String(bucket),
    60  		Key:    aws.String(prefix),
    61  	}
    62  
    63  	resp, err := svc.HeadObject(params)
    64  	if err != nil {
    65  		return 0, err
    66  	}
    67  
    68  	return *resp.ContentLength, nil
    69  }
    70  
    71  func parseFilename(keyString string) (filename string) {
    72  	ss := strings.Split(keyString, "/")
    73  	s := ss[len(ss)-1]
    74  	return s
    75  }
    76  
    77  func main() {
    78  	if len(os.Args) < 2 {
    79  		log.Println("USAGE ERROR: AWS_REGION=us-east-1 go run getObjWithProgress.go bucket-name object-key")
    80  		return
    81  	}
    82  
    83  	bucket := os.Args[1]
    84  	key := os.Args[2]
    85  
    86  	filename := parseFilename(key)
    87  
    88  	sess, err := session.NewSession()
    89  	if err != nil {
    90  		panic(err)
    91  	}
    92  
    93  	s3Client := s3.New(sess)
    94  	downloader := s3manager.NewDownloader(sess)
    95  	size, err := getFileSize(s3Client, bucket, key)
    96  	if err != nil {
    97  		panic(err)
    98  	}
    99  
   100  	log.Println("Starting download, size:", byteCountDecimal(size))
   101  	cwd, err := os.Getwd()
   102  	if err != nil {
   103  		panic(err)
   104  	}
   105  
   106  	temp, err := ioutil.TempFile(cwd, "getObjWithProgress-tmp-")
   107  	if err != nil {
   108  		panic(err)
   109  	}
   110  	tempfileName := temp.Name()
   111  
   112  	writer := &progressWriter{writer: temp, size: size, written: 0}
   113  	params := &s3.GetObjectInput{
   114  		Bucket: aws.String(bucket),
   115  		Key:    aws.String(key),
   116  	}
   117  
   118  	if _, err := downloader.Download(writer, params); err != nil {
   119  		log.Printf("Download failed! Deleting tempfile: %s", tempfileName)
   120  		os.Remove(tempfileName)
   121  		panic(err)
   122  	}
   123  
   124  	if err := temp.Close(); err != nil {
   125  		panic(err)
   126  	}
   127  
   128  	if err := os.Rename(temp.Name(), filename); err != nil {
   129  		panic(err)
   130  	}
   131  
   132  	fmt.Println()
   133  	log.Println("File downloaded! Available at:", filename)
   134  }