【问题标题】:Writing to byte range within a file in Go在 Go 中写入文件中的字节范围
【发布时间】:2018-12-05 06:29:17
【问题描述】:

我正在使用 GO 以 10MB 的并发块下载一个大文件,如下所示。

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "strconv"
)

func main() {
    chunkSize := 1024 * 1024 * 10 // 10MB
    url := "http://path/to/large/zip/file/zipfile.zip"
    filepath := "zipfile.zip"
    res, _ := http.Head(url)
    maps := res.Header
    length, _ := strconv.Atoi(maps["Content-Length"][0]) // Get the content length from the header request

    // startByte and endByte determines the positions of the chunk that should be downloaded
    var startByte = 0
    var endByte = chunkSize - 1

    for startByte < length {
        if endByte > length {
            endByte = length - 1
        }
        go func(startByte, endByte int) {
            client := &http.Client {}
            req, _ := http.NewRequest("GET", url, nil)

            rangeHeader := fmt.Sprintf("bytes=%d-%d", startByte, endByte)
            req.Header.Add("Range", rangeHeader)
            resp,_ := client.Do(req)
            defer resp.Body.Close()

            data, _ := ioutil.ReadAll(resp.Body)
            addToFile(filepath, startByte, endByte, data)
        }(startByte, endByte)

        startByte = endByte + 1
        endByte += chunkSize
    }
}

func addToFile(filepath string, startByte, endByte int, data []byte) {
    // TODO: write to byte range in file
}

我应该如何创建文件,并写入文件中与块的字节范围相对应的指定字节范围?

例如,如果我从字节 262144000-272629759 获取数据,则 addToFile 函数应写入 zipfile.zip 中的 262144000-272629759。然后,如果从另一个范围获取数据,则应将其写入 zipfile.zip 中的相应范围。

【问题讨论】:

  • 旁白:绑定检查应该是endByte &gt;= length

标签: file http go writefile


【解决方案1】:

想出了如何做到这一点。如下图改变addToFile函数。

func addToFile(filepath string, startByte int, data []byte) {
    f, err := os.OpenFile(filepath, os.O_CREATE | os.O_WRONLY, os.ModeAppend)
    if err != nil {
        panic("File not found")
    }
    whence := io.SeekStart
    _, err = f.Seek(int64(startByte), whence)
    f.Write(data)
    f.Sync() //flush to disk
    f.Close()
}

【讨论】:

    【解决方案2】:

    例如,

    package main
    
    import (
        "fmt"
        "io"
        "io/ioutil"
        "os"
    )
    
    func write(ws io.WriteSeeker, offset int64, p []byte) (n int, err error) {
        _, err = ws.Seek(offset, io.SeekStart)
        if err != nil {
            return 0, err
        }
        n, err = ws.Write(p)
        if err != nil {
            return 0, err
        }
        return n, nil
    }
    
    func main() {
        filename := `test.file`
        f, err := os.Create(filename)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            return
        }
        defer f.Close()
        buf := make([]byte, 16)
        for i := range buf {
            buf[i] = byte('A' + i)
        }
        _, err = write(f, 16, buf)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            return
        }
        for i := range buf {
            buf[i] = byte('a' + i)
        }
        _, err = write(f, 0, buf)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            return
        }
        err = f.Close()
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            return
        }
        data, err := ioutil.ReadFile(filename)
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            return
        }
        fmt.Printf("%q\n", data)
    }
    

    输出:

    "abcdefghijklmnopABCDEFGHIJKLMNOP"
    

    【讨论】:

      猜你喜欢
      • 2014-11-02
      • 2021-06-03
      • 2018-12-05
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      相关资源
      最近更新 更多