golang的io.copy使用

Posted smartrui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang的io.copy使用相关的知识,希望对你有一定的参考价值。

net/http 下载

在golang中,如果我们要下载一个文件,最简单的就是先用http.get()方法创建一个远程的请求后,后面可使用ioutil.WriteFile()等将请求内容直接写到文件中。

func DownFile() {
    url :="http://wx.qlogo.cn/Vaz7vE1/64"
    resp ,err := http.Get(url)
    if err != nil {
        fmt.Fprint(os.Stderr ,"get url error" , err)
    }

    defer resp.Body.Close()

    data ,err := ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }

     _ =ioutil.WriteFile("/tmp/icon_wx.png", data, 0755)
}

但是你会发现,上面的操作方式会有一个小问题,那就是下载小文件还行,如果是大的文件的话,可能会出现内存不足的问题,因为它是需要先把请求内容全部读取到内存中,然后再写入到文件中的。

那如果要下载大文件或者复制大文件,应该怎么办呢? 其实,Golang中就提供了 io.copy方法,它就是在文件指针之间直接复制的,不用全读入内存,可解决这样的问题。

io.copy

我们先看下原型声明

func Copy(dst Writer, src Reader) (written int64, err error) {
    return copyBuffer(dst, src, nil)
}

func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
    ....
    if buf == nil {
        size := 32 * 1024
        if l, ok := src.(*LimitedReader); ok && int64(size) > l.N {
            if l.N < 1 {
                size = 1
            } else {
                size = int(l.N)
            }
        }
        buf = make([]byte, size)
    }

它是将源复制到目标,并且是按默认的缓冲区32k循环操作的,不会将内容一次性全写入内存中,这样就能解决大文件的问题。

我们再用 io.copy 来实现一下吧。

func DownFile() {
    url :="http://wx.qlogo.cn/Vaz7vE1/64"
    resp ,err := http.Get(url)
    if err != nil {
        fmt.Fprint(os.Stderr ,"get url error" , err)
    }


    defer resp.Body.Close()
    
    out, err := os.Create("/tmp/icon_wx_2.png")
    wt :=bufio.NewWriter(out)
    
    defer out.Close()
    
    n, err :=io.Copy(wt, resp.Body)
    fmt.Println("write" , n)
    if err != nil {
        panic(err)
    }
    wt.Flush()
}

同理,如果我们要复制大文件也可以用 io.copy 这个,防止产生内存溢出。

以上是关于golang的io.copy使用的主要内容,如果未能解决你的问题,请参考以下文章

纯golang爬虫实战(三)

golang goroutine例子[golang并发代码片段]

golang代码片段(摘抄)

代码片段 - Golang 实现简单的 Web 服务器

代码片段 - Golang 实现集合操作

json [Golang] golang #golang #snippets中有用的片段