i have following code suppose download file splitting multiple parts. right works on images, when try downloading other files tar files output invalid file.
updated:
used os.writeat
instead of os.write
, removed os.o_append
file mode.
package main import ( "errors" "flag" "fmt" "io/ioutil" "log" "net/http" "os" "strconv" ) var file_url string var workers int var filename string func init() { flag.stringvar(&file_url, "url", "", "url of file download") flag.stringvar(&filename, "filename", "", "name of downloaded file") flag.intvar(&workers, "workers", 2, "number of download workers") } func get_headers(url string) (map[string]string, error) { headers := make(map[string]string) resp, err := http.head(url) if err != nil { return headers, err } if resp.statuscode != 200 { return headers, errors.new(resp.status) } key, val := range resp.header { headers[key] = val[0] } return headers, err } func download_chunk(url string, out string, start int, stop int) { client := new(http.client) req, _ := http.newrequest("get", url, nil) req.header.add("range", fmt.sprintf("bytes=%d-%d", start, stop)) resp, _ := client.do(req) defer resp.body.close() body, err := ioutil.readall(resp.body) if err != nil { log.fatalln(err) return } file, err := os.openfile(out, os.o_wronly, 0600) if err != nil { if file, err = os.create(out); err != nil { log.fatalln(err) return } } defer file.close() if _, err := file.writeat(body, int64(start)); err != nil { log.fatalln(err) return } fmt.println(fmt.sprintf("range %d-%d: %d", start, stop, resp.contentlength)) } func main() { flag.parse() headers, err := get_headers(file_url) if err != nil { fmt.println(err) } else { length, _ := strconv.atoi(headers["content-length"]) bytes_chunk := length / workers fmt.println("file length: ", length) := 0; < workers; i++ { start := * bytes_chunk stop := start + (bytes_chunk - 1) go download_chunk(file_url, filename, start, stop) } var input string fmt.scanln(&input) } }
basically, reads length of file, divides number of workers each file downloads using http's range header, after downloading seeks position in file chunk written.
if ignore many errors seen above code not supposed work reliably file type.
however, guess can see on problem in code. think mixing o_append , seek mistake (seek should ignored mode). suggest use (*os.file).writeat instead.
iirc, o_append forces write happen @ [current] end of file. however, download_chunk
function instances file parts can executing in unpredictable order, "reordering" file parts. result corrupted file.