在 GO 中重组大块 zip 下载

我正在与 Accept-Ranges 和 Goroutines 并行下载一个大的 .zip 文件。该应用程序使用其 Range 标头发送多个请求,以从 URL 下载 10MB 的 zip 文件块。


请求被分成不同的范围作为单独的 Goroutines,并将获得的数据写入临时文件。这些文件被命名为 1、2、3....


package main


import (

    "bufio"

    "fmt"

    "io"

    "io/ioutil"

    "log"

    "net/http"

    "os"

    "strconv"

    "sync"

)


var wg sync.WaitGroup


func main() {

    url := "https://path/to/large/zip/file/zipfile.zip"

    res, _ := http.Head(url)

    maps := res.Header

    length, _ := strconv.Atoi(maps["Content-Length"][0]) // Get the content length from the header request

    chunks := (length / (1024 * 1024 * 10)) + 1


    // startByte and endByte determines the positions of the chunk that should be downloaded

    var startByte = 0

    var endByte = (1024 * 1024 * 10) - 1

    //body := make([][]byte, chunks)

    body := make([]io.ReadCloser, chunks)


    for i := 0; i < chunks; i++ {

        wg.Add(1)


        go func(min int, max int, i int) {

            client := &http.Client {}

            req, _ := http.NewRequest("GET", url, nil)

            rangeHeader := "bytes=" + strconv.Itoa(min) +"-" + strconv.Itoa(max)

            fmt.Println(rangeHeader)

            req.Header.Add("Range", rangeHeader)


            resp,_ := client.Do(req)

            defer resp.Body.Close()


            reader, _ := ioutil.ReadAll(resp.Body)

            body[i] = resp.Body

            ioutil.WriteFile(strconv.Itoa(i), reader, 777) // Write to the file i as a byte array


            wg.Done()

        }(startByte, endByte, i)


        startByte = endByte + 1

        endByte += 1024 * 1024 * 10

    }

    wg.Wait()


    filepath := "zipfile.zip"

    // Create the file

    _, err := os.Create(filepath)

    if err != nil {

        return

    }

    file, _ := os.OpenFile(filepath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)

    if err != nil {

        log.Fatal(err)

    }



下载完所有文件后,我尝试将它们重新组合成一个 .zip 文件。但是,当文件放在一起时,我无法解压缩最终文件,因为它似乎已损坏。


我想知道我做错了什么,或者是否有更好的方法。提前致谢。



慕无忌1623718
浏览 77回答 1
1回答

紫衣仙女

问题在于您的范围请求线条&nbsp; &nbsp;resp,_ := client.Do(req)&nbsp; &nbsp;defer resp.Body.Close()go vet由于未检查错误而被报告。如果您检查最后一个块中的响应代码是 416 - 这是使用的不正确范围,请更改为resp, err := client.Do(req)if err != nil {&nbsp; &nbsp; panic(err)}if resp.StatusCode == 416 {&nbsp; &nbsp; fmt.Println("incorrect range")}defer resp.Body.Close()我还将循环变量更改为for i := 0; i < chunks-1; i++ { 并更改了 go 例程之后的部分startByte = endByte + 1endByte += 1024 * 1024 * 10if startByte >= length {&nbsp; &nbsp; break}for endByte >= length {&nbsp; &nbsp; endByte = endByte - 1}并以类似的方式改变 j 循环变量这些更改似乎对我有用,但我没有合适的测试数据来真正检查
打开App,查看更多内容
随时随地看视频慕课网APP