使用|使用 go 实现多线程下载器的方法

目录

  • 1.多线程下载原理
  • 2.构造一个下载器
    • 2.1 为下载器提供初始化方法
  • 3.实现下载综合调度逻辑
    • 3.1 下载文件分段
    • 3.2 子线程下载函数
  • 4. 保存下载文件函数
    • 5.完整代码
      本篇文章我们用Go实现一个简单的多线程下载器。

      1.多线程下载原理 通过判断下载文件链接返回头信息中的 Accept-Ranges 字段,如果为 bytes 则表示支持断点续传。
      然后在请求头中设置 Range 字段为 bytes=[start]-[end],以请求下载文件的分段部分,然后将所有分段合并为一个完整文件。

      2.构造一个下载器
      type HttpDownloader struct { url stringfilename stringcontentLength intacceptRanges bool// 是否支持断点续传numThreads int// 同时下载线程数}


      2.1 为下载器提供初始化方法
      func New(url string, numThreads int) *HttpDownloader {var urlSplits []string = strings.Split(url, "/")var filename string = urlSplits[len(urlSplits)-1]res, err := http.Head(url)check(err)httpDownload := new(HttpDownloader)httpDownload.url = urlhttpDownload.contentLength = int(res.ContentLength)httpDownload.numThreads = numThreadshttpDownload.filename = filenameif len(res.Header["Accept-Ranges"]) != 0 && res.Header["Accept-Ranges"][0] == "bytes" {httpDownload.acceptRanges = true} else {httpDownload.acceptRanges = false}return httpDownload}


      3.实现下载综合调度逻辑 如果不支持多线程下载,就使用单线程下载。
      func (h *HttpDownloader) Download() {f, err := os.Create(h.filename)check(err)defer f.Close()if h.acceptRanges == false {fmt.Println("该文件不支持多线程下载,单线程下载中:")resp, err := http.Get(h.url)check(err)save2file(h.filename, 0, resp)} else {var wg sync.WaitGroupfor _, ranges := range h.Split() {fmt.Printf("多线程下载中:%d-%d\n", ranges[0], ranges[1])wg.Add(1)go func(start, end int) {defer wg.Done()h.download(start, end)}(ranges[0], ranges[1])}wg.Wait()}}


      3.1 下载文件分段
      func (h *HttpDownloader) Split() [][]int {ranges := [][]int{}blockSize := h.contentLength / h.numThreadsfor i:=0; i

      3.2 子线程下载函数
      func (h *HttpDownloader) download(start, end int) {req, err := http.NewRequest("GET", h.url, nil)check(err)req.Header.Set("Range", fmt.Sprintf("bytes=%v-%v", start, end))req.Header.Set("User-Agent", userAgent)resp, err := http.DefaultClient.Do(req)check(err)defer resp.Body.Close() save2file(h.filename, int64(start), resp)}


      4. 保存下载文件函数
      func save2file(filename string, offset int64, resp *http.Response) {f, err := os.OpenFile(filename, os.O_WRONLY, 0660)check(err)f.Seek(offset, 0)defer f.Close()content, err := ioutil.ReadAll(resp.Body)check(err)f.Write(content)}


      5.完整代码
      package mainimport ("fmt""strings""log""os""net/http""sync""io/ioutil")const (userAgent = `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36`)type HttpDownloader struct { url stringfilename stringcontentLength intacceptRanges bool// 是否支持断点续传numThreads int// 同时下载线程数} func check(e error) {if e != nil {log.Println(e)panic(e)}}func New(url string, numThreads int) *HttpDownloader {var urlSplits []string = strings.Split(url, "/")var filename string = urlSplits[len(urlSplits)-1]res, err := http.Head(url)check(err)httpDownload := new(HttpDownloader)httpDownload.url = urlhttpDownload.contentLength = int(res.ContentLength)httpDownload.numThreads = numThreadshttpDownload.filename = filenameif len(res.Header["Accept-Ranges"]) != 0 && res.Header["Accept-Ranges"][0] == "bytes" {httpDownload.acceptRanges = true} else {httpDownload.acceptRanges = false}return httpDownload}// 下载综合调度func (h *HttpDownloader) Download() {f, err := os.Create(h.filename)check(err)defer f.Close()if h.acceptRanges == false {fmt.Println("该文件不支持多线程下载,单线程下载中:")resp, err := http.Get(h.url)check(err)save2file(h.filename, 0, resp)} else {var wg sync.WaitGroupfor _, ranges := range h.Split() {fmt.Printf("多线程下载中:%d-%d\n", ranges[0], ranges[1])wg.Add(1)go func(start, end int) {defer wg.Done()h.download(start, end)}(ranges[0], ranges[1])}wg.Wait()}}// 下载文件分段func (h *HttpDownloader) Split() [][]int {ranges := [][]int{}blockSize := h.contentLength / h.numThreadsfor i:=0; i
      【使用|使用 go 实现多线程下载器的方法】到此这篇关于使用 go 实现多线程下载器的文章就介绍到这了,更多相关go多线程下载器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

        推荐阅读