当前位置: 首页 > news >正文

golang实现可中断的流式下载

golang实现可中断的流式下载

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

  1. 从服务器上读取文件,返回一个ReadCloser
  2. 在用户磁盘上创建文件,通过io.Copy实现文件下载(io.Copy是流式的操作,不会出现因文件过大而内存暴涨的问题)
  3. 通过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.Bodydefer 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 canceledcase <-ctx.Done():// stop process and propagate "context canceled" errorreturn 0, NewIoCopyCancelledErr(ctx.Err().Error())default:// otherwise just run default io.Reader implementationreturn src.Read(p)}}))return size, err
}
http://www.lryc.cn/news/271083.html

相关文章:

  • SpringBoot 医药咨询系统
  • C语言转WebAssembly的全流程,及Web端调用测试
  • 前端--基础 目录文件夹和根目录 VScode打开目录文件夹
  • 传感器原理与应用复习--超声波、微波、红外及热电偶传感器
  • matlab概率论例子
  • Appium+python自动化(一)- 环境搭建—上(超详解)
  • 基于SpringBoot的精简博客系统
  • STM32的在线升级(IAP)实现方法:BOOT+APP原理详解
  • 【芯片DFX】Arm调试架构篇
  • ES应用_ES实战
  • Ubuntu上如何找到设备,打印串口日志
  • 本地映射测试环境域名,解决登录测试环境后,也可以使用本地域名访问,可以正常跑本地项目
  • VSCode使用Remote SSH远程连接Windows 7
  • uniapp中uview组件库丰富的Calendar 日历用法
  • 云原生Kubernetes:K8S集群实现容器运行时迁移(docker → containerd) 与 版本升级(v1.23.14 → v1.24.1)
  • Redis 数据结构和常用命令
  • Docker 容器命令总汇
  • react + redux 之 美团案例
  • 【形式语言与自动机/编译原理】CFG-->Greibach-->NPDA(2)
  • 14.用户管理
  • 【交叉编译环境】安装arm-linux交叉编译环境到虚拟机教程(简洁版本)
  • 感染了后缀为.[sqlback@memeware.net].2700勒索病毒如何应对?数据能够恢复吗?
  • [Linux开发工具]——vim使用
  • 【教学类-43-11】 20231231 3*3宫格数独提取单元格坐标数字的通用模板(做成2*2=4套、3*2=6套)
  • Spring Boot日志:从Logger到@Slf4j的探秘
  • 英飞凌TC3xx之一起认识GTM系列(六)如何实现GTM与VADC关联的配置
  • 【基础】【Python网络爬虫】【6.数据持久化】Excel、Json、Csv 数据保存(附大量案例代码)(建议收藏)
  • 王道考研计算机网络——应用层
  • Android MVVM 写法
  • LeetCode 热题 100——283. 移动零