Go file downloader -


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.