golang实现可中断的流式下载功能

 更新时间:2024年01月02日 09:12:45   作者:NPE~  
这篇文章主要给大家介绍了golang实现可中断的流式下载,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下

golang实现可中断的流式下载

最近有一个需要实现下载功能:

从服务器上读取文件,返回一个ReadCloser

在用户磁盘上创建文件,通过io.Copy实现文件下载(io.Copy是流式的操作,不会出现因文件过大而内存暴涨的问题)

通过context实现暂停

1 流式下载:io.Copy

这里拷贝文件我们选择的是io.Copy而非是通过ioutil.ReadAll()将body中返回的数据一次性读取到内存

通过io.Copy可以保证内存占用一直处于一个比较稳定的水平

2 可中断:context

通过封装io.Copy实现

  • 将io.Copy封装为一个方法,方法里传入context,外部通过context.WithCancel()控制流式拷贝的暂停

3 全部代码

这里演示我通过读取S3的一个对象下载到本地

/*
	通过io.Copy实现可中断的流复制
*/
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实现可中断的流拷贝
// 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实现可中断的流式下载的详细内容,更多关于golang实现流式下载的资料请关注脚本之家其它相关文章!

相关文章

  • golang进行xml文件解析的操作方法

    golang进行xml文件解析的操作方法

    本文介绍了Go语言中解析XML文件的几种方法:小文件解析、大文件流式解析和复杂结构解析,对于小文件,使用标准库中的encoding/xml包;对于大文件,采用流式解析以避免内存溢出,对于复杂结构的XML文件,推荐使用第三方库github.com/beevik/etree
    2024-11-11
  • 创建Go工程化项目布局详解

    创建Go工程化项目布局详解

    这篇文章主要介绍了创建Go工程化项目布局详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • golang数组和切片作为参数和返回值的实现

    golang数组和切片作为参数和返回值的实现

    本文主要介绍了golang数组和切片作为参数和返回值的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 详解go-zero是如何做路由管理的

    详解go-zero是如何做路由管理的

    go-zero 是一个微服务框架,包含了 web 和 rpc 两大部分,而对于 web 框架来说,路由管理是必不可少的一部分,那么本文就来探讨一下 go-zero 的路由管理是怎么做的吧
    2023-08-08
  • Golang的循环语句和循环控制语句详解

    Golang的循环语句和循环控制语句详解

    循环语句为了简化程序中有规律的重复性操作,需要用到循环语句,和其他大多数编程语言一样,GO的循环语句有for循环,不同的是没有while循环,而循环控制语句可以改变循环语句的执行过程,下面给大家介绍下go循环语句和循环控制语句的相关知识,一起看看吧
    2021-11-11
  • 线上问题排查之golang使用json进行对象copy

    线上问题排查之golang使用json进行对象copy

    这篇文章主要介绍了线上问题排查之golang使用json进行对象copy,文章围绕golang使用json进行对象copy的内存溢出问题排查展开详细内容需要的小伙伴可以参考一下
    2022-06-06
  • Go使用Gin+mysql实现增删改查的详细实例

    Go使用Gin+mysql实现增删改查的详细实例

    golang本身没有提供连接mysql的驱动,但是定义了标准接口供第三方开发驱动,下面这篇文章主要给大家介绍了关于Go使用Gin+mysql实现增删改查的相关资料,需要的朋友可以参考下
    2022-12-12
  • 一键定位Golang线上服务内存泄露的秘籍

    一键定位Golang线上服务内存泄露的秘籍

    内存泄露?别让它拖垮你的Golang线上服务!快速掌握Go语言服务内存泄漏排查秘籍,从此问题无处遁形,一文读懂如何精准定位与有效解决Golang应用中的内存问题,立即阅读,让性能飞升!
    2024-01-01
  • goland中npm无法使用的问题及解决

    goland中npm无法使用的问题及解决

    这篇文章主要介绍了goland中npm无法使用的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Golang变量直接初始化的方法详解

    Golang变量直接初始化的方法详解

    在 Go 语言中,我们常用的数据结构有在Go语言中,你可以初始化不同的数据结构,例如数组、切片、结构体、指针、map等,本文将给大家介绍一下Golang变量直接初始化的方法,需要的朋友可以参考下
    2023-08-08

最新评论