使用 Go 语言下载一个文件,大家一般会怎么做呢,比如,我们要下载 https://www.twle.cn/static/i/img1.jpg 这张图片。
前面的部分,想必很多人都一样,使用 net/http 包下的 http.Get() 方法创建一个到远程图片的请求。
代码一般如下
package main
import (
"net/http"
)
func main() {
imgUrl := "https://www.twle.cn/static/i/img1.jpg"
// Get the data
resp, err := http.Get(imgUrl)
if err != nil {
return err
}
defer resp.Body.Close()
}
但接下来呢 ? 实现方式就有很多了
最常见的应该是使用 io/ioutil 包下的 io.WriteFile() 函数直接将响应写入到一个文件中
package main
import (
"io/ioutil"
"net/http"
)
func main() {
imgUrl := "https://www.twle.cn/static/i/img1.jpg"
// Get the data
resp, err := http.Get(imgUrl)
if err != nil {
panic(err)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
ioutil.WriteFile("img1.jpg", data, 0644)
}
大家有没有发现这种实现方式有一个弱点? 我们需要使用 ioutil.ReadAll(resp.Body) 先将所有的响应读出来放到内存中。如果文件太大,那么就会消耗很多内存。这样是不明智的。
幸好,io 包提供了 io.Copy() 方法,该方法实现了两个文件句柄之间的拷贝。
io.Copy() 方法
io.Copy() 方法实现了两个文件指针之间的内容拷贝。该方法的原型如下
func Copy(dst Writer, src Reader) (written int64, err error)
io.Copy() 方法将副本从 src 复制到 dst ,直到 src 达到文件末尾 ( EOF ) 或发生错误,然后返回复制的字节数和复制时遇到的第一个错误( 如果有 )
有了这个函数,我们就省去了先把内容读取到内存,然后将内存中的内容写到文件的过程,于是,我们的代码就可以改成如下方式
package main
import (
"io"
"net/http"
"os"
)
func main() {
imgUrl := "https://www.twle.cn/static/i/img1.jpg"
// Get the data
resp, err := http.Get(imgUrl)
if err != nil {
panic(err)
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create("img1.jpg")
if err != nil {
panic(err)
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil {
panic(err)
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。