Запись в диапазон байтов в файле в Go - PullRequest
0 голосов
/ 05 декабря 2018

Я загружаю большой файл в параллельных блоках по 10 МБ, используя GO, как показано ниже.

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 должна записать 262144000-272629759 в zipfile.zip.Затем, если получены данные из другого диапазона, они должны быть записаны в соответствующий диапазон в zipfile.zip.

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Например,

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"
0 голосов
/ 05 декабря 2018

Разобрался, как это сделать.Измените функцию 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()
}
...