复制文件(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循环操做的, 不会将内容一次性全写入内存中, 能够防止产生内存溢出, 特别是超大文件。
使用案例: 复制文件
package main
import (
"fmt"
"io"
"log"
"os"
)
// 封装 复制文件的方法 已经复制的情况下,可以重复复制
func copy(src, dst string) (int64, error) {
// 判断文件的状态
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}
// 判断是否是正常的文件
if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}
// 打开文件
source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()
// 创建文件
destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
// 开始复制
size, err := io.Copy(destination, source)
return size, err
}
func main() {
filesize, err := copy("context.zip", "xuchenkai.zip")
if err != nil {
log.Printf("%v", err)
}
log.Printf("文件已经复制成功, 大小:%v", filesize)
}
使用案例: 下载文件
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()
/*
//方式一: ioutil.ReadAll
// 使用 ioutil.ReadAll(resp.Body) 先将所有的响应读出来放到内存中。如果文件太大,那么就会消耗很多内存, 导致内存溢出。
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
ioutil.WriteFile("img1.jpg", data, 0644)
*/
// 方式二: io.Copy
// 创建一个文件用于保存
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)
}
}