golang實現(xiàn)可中斷的流式下載功能
golang實現(xiàn)可中斷的流式下載
最近有一個需要實現(xiàn)下載功能:
從服務器上讀取文件,返回一個ReadCloser
在用戶磁盤上創(chuàng)建文件,通過io.Copy實現(xiàn)文件下載(io.Copy是流式的操作,不會出現(xiàn)因文件過大而內(nèi)存暴漲的問題)
通過context實現(xiàn)暫停
1 流式下載:io.Copy
這里拷貝文件我們選擇的是io.Copy而非是通過ioutil.ReadAll()將body中返回的數(shù)據(jù)一次性讀取到內(nèi)存
通過io.Copy可以保證內(nèi)存占用一直處于一個比較穩(wěn)定的水平
2 可中斷:context
通過封裝io.Copy實現(xiàn)
- 將io.Copy封裝為一個方法,方法里傳入context,外部通過context.WithCancel()控制流式拷貝的暫停
3 全部代碼
這里演示我通過讀取S3的一個對象下載到本地
/*
通過io.Copy實現(xiàn)可中斷的流復制
*/
var (
ak = "99999999999999999999"
sk = "9999999999999999999999999999999999999999"
endpoint = "http://xx.xx.xx.xx:8060"
bucket = "test-bucket"
key = "d_xp/2G/2G.txt"
)
func main() {
s3Client := osg.Client.GetS3Client(ak, sk, endpoint)
ctx, cancelFunc := context.WithCancel(context.Background())
object, err := s3Client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
go func() {
time.Sleep(time.Second * 10)
cancelFunc()
log.Infof("canceled...")
}()
if err != nil {
log.Errorf("%v", err)
return
}
body := object.Body
defer body.Close()
file, err := os.Create("/Users/ziyi/GolandProjects/MyTest/demo_home/io_demo/target.txt")
if err != nil {
log.Errorf("%v", err)
return
}
defer file.Close()
_, err = FileService.Copy(ctx, file, body)
if err != nil {
log.Errorf("%v", err)
return
}
}
type fileService struct {
sem *semaphore.Weighted
}
var FileService = &fileService{
sem: semaphore.NewWeighted(1),
}
type IoCopyCancelledErr struct {
errMsg string
}
func (e *IoCopyCancelledErr) Error() string {
return fmt.Sprintf("io copy error, %s", e.errMsg)
}
func NewIoCopyCancelledErr(msg string) *IoCopyCancelledErr {
return &IoCopyCancelledErr{
errMsg: msg,
}
}
type readerFunc func(p []byte) (n int, err error)
func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) }
//通過ctx實現(xiàn)可中斷的流拷貝
// Copy closable copy
func (s *fileService) Copy(ctx context.Context, dst io.Writer, src io.Reader) (int64, error) {
// Copy will call the Reader and Writer interface multiple time, in order
// to copy by chunk (avoiding loading the whole file in memory).
// I insert the ability to cancel before read time as it is the earliest
// possible in the call process.
size, err := io.Copy(dst, readerFunc(func(p []byte) (int, error) {
select {
// if context has been canceled
case <-ctx.Done():
// stop process and propagate "context canceled" error
return 0, NewIoCopyCancelledErr(ctx.Err().Error())
default:
// otherwise just run default io.Reader implementation
return src.Read(p)
}
}))
return size, err
}
以上就是golang實現(xiàn)可中斷的流式下載的詳細內(nèi)容,更多關(guān)于golang實現(xiàn)流式下載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言kube-scheduler深度剖析開發(fā)之scheduler初始化
這篇文章主要介紹了Go語言kube-scheduler深度剖析開發(fā)之scheduler初始化實現(xiàn)過程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04
golang給函數(shù)參數(shù)設置默認值的幾種方式小結(jié)(函數(shù)參數(shù)默認值
在日常開發(fā)中我們有時候需要使用默認設置,下面這篇文章主要給大家介紹了關(guān)于golang給函數(shù)參數(shù)設置默認值的幾種方式小結(jié)的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-01-01
Go語言中的package和go modules的實現(xiàn)
本文主要介紹了Go語言中的package和go modules的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-07-07
golang開發(fā)?gorilla?websocket的使用示例詳解
這篇文章主要介紹了golang開發(fā)?gorilla?websocket的使用示例詳解,介紹了websocket的簡單使用,我們使用的版本是1.3.0,具體操作方法跟隨小編一起學習吧2024-05-05
Go語言-為什么返回值為接口類型,卻返回結(jié)構(gòu)體
這篇文章主要介紹了Go語言返回值為接口類型,卻返回結(jié)構(gòu)體的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
Go語言字典(map)用法實例分析【創(chuàng)建,填充,遍歷,查找,修改,刪除】
這篇文章主要介紹了Go語言字典(map)用法,結(jié)合實例形式較為詳細的分析了Go語言字典的創(chuàng)建、填充、遍歷、查找、修改、刪除等操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2017-02-02

