先看看普通的上传文件代码:
func uploadfile(w http.ResponseWriter, r *http.Request){ // 根据字段名获取表单文件 formFile, header, err := r.FormFile("uploadfile") if err != nil { log.Printf("Get form file failed: %s\n", err) return } defer formFile.Close() // 创建保存文件 destFile, err := os.Create("./upload/" + header.Filename) if err != nil { log.Printf("Create failed: %s\n", err) return } defer destFile.Close() // 读取表单文件,写入保存文件 _, err = io.Copy(destFile, formFile) if err != nil { log.Printf("Write file failed: %s\n", err) return } }
这种方式比较简单,缺点是程序底层会先把文件接收并存入临时文件中,还有就是无法管控数据传输过程,比如上传速度限制。
关于如何自定义接收上传文件,我会贴出代码并讲解( 看注释 ),代码是从我自己项目中抠出来的,所以无法直接运行
// Upload 接收上传文件,支持限速
// path: 文件存放目录
// fname: 文件名,为空表示使用上传文件名
// maxSize: 文件最大字节数,必要参数
// speed: 每秒上传字节数,0表示不限速
func (c *ControllerBase) Upload(path, fname string, maxSize, speed int64)
(string, string, int64, error) {
// c.Ctx.R 是 *http.Request
// MultipartReader 返回一个MIME multipart读取器,上传文件就是从*multipart.Reader里读取的。
// 不能调用ParseMultipartForm,因为会导致*multipart.Reader中的数据被自动读取,
上传文件也会被读取并写入临时文件。
mr, err := c.Ctx.R.MultipartReader()
if err != nil {
return "", "", 0, err
}
var (
filename string
num int64
)
// 循环读取post请求参数,上传文件就在其中
for {
// NextPart 返回multipart,multipart可能是上传文件,也可能是普通post参数
p, err := mr.NextPart()
if err != nil {
if err == io.EOF {
break
}
return "", "", 0, err
}
// 从multipart获取上传文件的参数名,如果为空表示该参数不是上传文件,
continue处理下一个参数,直到遇到上传文件或结束。
filename = p.FileName()
if len(filename) == 0 {
continue
}
if len(fname) == 0 {
fname = filename
}
// 组装文件路径并创建文件,然后就可以直接写入。
path += fname
f, err := os.Create(path)
if err != nil {
return "", "", 0, err
}
maxSize++
if speed == 0 {
// 正常复制数据,不限速
num, err = io.CopyN(f, p, maxSize)
} else {
// 限制上传速度,使用了我的另一个限速工具,详见:blog.gaoge.ink/category/11.html
num, err = io.CopyN(f, ratelimit.Reader(p, ratelimit.New(speed)), maxSize)
}
// 到这里,文件传输过程结束了。比起普通上传文件方式,
不生成临时文件提高了效率,还可以手动处理数据传输过程
,来实现限速和限制文件大小等功能。
f.Close()
if err == io.EOF {
return path, filename, num, nil
}
// 如果传输文件没有等到返回EOF,表示文件大小超过了maxSize
os.Remove(path)
return "", "", num, errors.New("文件太大")
}
return "", "", 0, nil
}
嗯嗯,就这样,然后该说点什么呢
谢谢阅读