Skip to content

Instantly share code, notes, and snippets.

@XUJiahua
Created October 18, 2015 09:10
Show Gist options
  • Save XUJiahua/27fc59647298cf59edbc to your computer and use it in GitHub Desktop.
Save XUJiahua/27fc59647298cf59edbc to your computer and use it in GitHub Desktop.
/**
理论基础: https://en.wikipedia.org/wiki/Byte_serving
使用range header可以得到网络资源的一部分字节
*/
package main
import (
"net/http"
"fmt"
"os"
"io/ioutil"
"strconv"
)
func myPanic(err error) {
fmt.Printf("%s\n", err)
os.Exit(1)
}
const url = "http://download.cardinfolink.net/android/showmoney.apk"
const threadNum = 3
func getPartOfFile(start, end int) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
rangeVal := fmt.Sprintf("bytes=%d-%d", start, end)
req.Header.Set("Range", rangeVal)
response, err := client.Do(req)
if err != nil {
return nil, err
}
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
fmt.Println("getPartOfFile done")
c <- FilePiece{start:start, end:end, contents:contents}
return contents, nil
}
type FilePiece struct {
start, end int
contents []byte
}
const filename = "/Users/jiahua/Downloads/xxx.apk"
var c = make(chan FilePiece, threadNum)
func main() {
res, err := http.Head(url)
if err != nil {
myPanic(err)
}
fileLen, err := strconv.Atoi(res.Header.Get("Content-Length"))
if err != nil {
myPanic(err)
}
blockSize := fileLen / threadNum
remainingSize := fileLen % threadNum
fmt.Printf("fileSize: %d, blockSize for each thread: %d, remainingSize: %d\n", fileLen, blockSize, remainingSize)
for i := 0; i < threadNum; i++ {
start := i * blockSize
end := (i + 1) * blockSize - 1
if threadNum - 1 == i {
end += remainingSize
}
fmt.Printf("Thread%d, start: %d end: %d\n", i, start, end)
go getPartOfFile(start, end)
}
file, err := os.Create(filename)
if err != nil {
myPanic(err)
}
defer file.Close()
for i := 0; i < threadNum; i++ {
//routine返回的结果
fp := <-c
fmt.Printf("Content received, start: %d end: %d\n", fp.start, fp.end)
// WriteAt会overwrite原有数据,之前一段不存在也能写入..
_, err := file.WriteAt(fp.contents, int64(fp.start))
if err != nil {
myPanic(err)
}
}
file.Sync()
fmt.Println("File download Done")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment