为了账号安全,请及时绑定邮箱和手机立即绑定

在 GO 中重组大块 zip 下载

在 GO 中重组大块 zip 下载

Go
慕无忌1623718 2023-05-15 14:35:05
我正在与 Accept-Ranges 和 Goroutines 并行下载一个大的 .zip 文件。该应用程序使用其 Range 标头发送多个请求,以从 URL 下载 10MB 的 zip 文件块。请求被分成不同的范围作为单独的 Goroutines,并将获得的数据写入临时文件。这些文件被命名为 1、2、3....package mainimport (    "bufio"    "fmt"    "io"    "io/ioutil"    "log"    "net/http"    "os"    "strconv"    "sync")var wg sync.WaitGroupfunc 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 文件。但是,当文件放在一起时,我无法解压缩最终文件,因为它似乎已损坏。我想知道我做错了什么,或者是否有更好的方法。提前致谢。
查看完整描述

1 回答

?
紫衣仙女

TA贡献1839条经验 获得超15个赞

问题在于您的范围请求


线条


   resp,_ := client.Do(req)

   defer resp.Body.Close()

go vet由于未检查错误而被报告。如果您检查最后一个块中的响应代码是 416 - 这是使用的不正确范围,请更改为


resp, err := client.Do(req)

if err != nil {

    panic(err)

}

if resp.StatusCode == 416 {

    fmt.Println("incorrect range")

}

defer resp.Body.Close()

我还将循环变量更改为for i := 0; i < chunks-1; i++ { 并更改了 go 例程之后的部分


startByte = endByte + 1

endByte += 1024 * 1024 * 10

if startByte >= length {

    break

}

for endByte >= length {

    endByte = endByte - 1

}

并以类似的方式改变 j 循环变量


这些更改似乎对我有用,但我没有合适的测试数据来真正检查


查看完整回答
反对 回复 2023-05-15
  • 1 回答
  • 0 关注
  • 73 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信