import("fmt""io""net/http""os""strings""testing")funcTestDownload(t *testing.T){
fmt.Println("Download Started")
fileUrl :="https://dl.google.com/go/go1.11.1.src.tar.gz"
err :=DownloadFile("go1.11.1.src.tar.gz", fileUrl)if err !=nil{panic(err)}
fmt.Println("Download Finished")}// WriteCounter counts the number of bytes written to it. It implements to the io.Writer// interface and we can pass this into io.TeeReader() which will report progress on each// write cycle.type WriteCounter struct{
Total uint64}func(wc *WriteCounter)Write(p []byte)(int,error){// 该方法会在 io.Copy 源码里面 读取 TeeReader返回的reader 然后 读取 read 并且读取 w.Write 方法 也就是当前的 (wc *WriteCounter) Write(
n :=len(p)
wc.Total +=uint64(n)
wc.PrintProgress()return n,nil}func(wc *WriteCounter)PrintProgress(){// Clear the line by using a character return to go back to the start and remove// the remaining characters by filling it with spaces
fmt.Printf("\r%s", strings.Repeat(" ",35))// Return again and print current status of download// We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB)
fmt.Printf("\rDownloading... %d B complete", wc.Total)}funcmain(){}// DownloadFile will download a url to a local file. It's efficient because it will// write as it downloads and not load the whole file into memory. We pass an io.TeeReader// into Copy() to report progress on the download.funcDownloadFile(filepath string, url string)error{// Create the file, but give it a tmp file extension, this means we won't overwrite a// file until it's downloaded, but we'll remove the tmp extension once downloaded.// Get the data
resp, err := http.Get(url)if err !=nil{return err
}defer resp.Body.Close()
out, err := os.Create(filepath +".tmp")if err !=nil{return err
}// Create our progress reporter and pass it to be used alongside our writer
counter :=&WriteCounter{}// io.Copy read 方法 会执行接口 io.TeeReader (read -> writer 方法)_, err = io.Copy(out, io.TeeReader(resp.Body, counter))if err !=nil{return err
}
out.Close()// The progress use the same line so print a new line once it's finished downloading
fmt.Print("\n")
err = os.Rename(filepath+".tmp", filepath)if err !=nil{return err
}returnnil}
其他
funcTestMains(t *testing.T){
r := strings.NewReader("some io.Reader stream to be read\n")var buf bytes.Buffer
tee := io.TeeReader(r,&buf)
printall :=func(r io.Reader){
b, err := ioutil.ReadAll(r)if err !=nil{
t.Fatal(err)}
fmt.Printf("%s", b)}printall(tee)printall(&buf)}