赞
踩
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。
在之前的文章中,我们讲解了Gin框架的快速入门使用,今天我们来聊聊如何使用Gin实现文件上传。
Go标准库net/http对文件上传已经提供了非常完善的支持,而Gin框架在其基础上进一步封装,因此使用Gin开发文件上传功能时,只需要简单几行代码便可以实现,Gin框架支持单个文件与多个文件同时上传。
目录
我们首先看看实现一个HTTP服务器,提供文件上传功能的简单示例
- package main
-
- import (
- "io"
- "io/ioutil"
- "log"
- "net/http"
-
- "github.com/julienschmidt/httprouter"
- )
-
- const (
- MAX_UPLOAD_SIZE = 1024 * 1024 * 20 //最大上传大小,50MB
- )
-
- func main() {
- r := RegisterHandlers()
-
- http.ListenAndServe(":8080", r) // 开启一个http服务
- }
-
- // 定义路由
- func RegisterHandlers() *httprouter.Router {
- router := httprouter.New()
-
- router.POST("/upload", uploadHandler)
-
- return router
- }
- // 文件上传接口
- func uploadHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
- r.Body = http.MaxBytesReader(w, r.Body, MAX_UPLOAD_SIZE)
- if err := r.ParseMultipartForm(MAX_UPLOAD_SIZE); err != nil {
- log.Printf("File is too big")
- return
- }
- file, headers, err := r.FormFile("file")
- if err != nil {
- log.Printf("Error when try to get file: %v", err)
- return
- }
- //获取上传文件的类型
- if headers.Header.Get("Content-Type") != "image/png" {
- log.Printf("只允许上传png图片")
- return
- }
- data, err := ioutil.ReadAll(file)
- if err != nil {
- log.Printf("Read file error: %v", err)
- return
- }
- fn := headers.Filename
- err = ioutil.WriteFile("./video/"+fn, data, 0666)
- if err != nil {
- log.Printf("Write file error: %v", err)
- return
- }
- w.WriteHeader(http.StatusCreated)
- io.WriteString(w, "Uploaded successfully")
- }
如上我们通过r.FormFile函数获取上传的文件对象,以及文件的相关信息。然后通过headers.Header.Get函数获取上传文件的类型,判断类型是否符合要求。接着,使用ioutil.ReadAll函数读取文件的内容,并将其存储在data变量中。然后,通过headers.Filename获取上传文件的文件名,并使用ioutil.WriteFile函数将文件内容写入到指定路径下的文件中。
单文件上传使用gin.Context的FormFile()方法,该方法的值为POST请求中文件上传字段的名称:
- engine := gin.Default()
- engine.POST("/upload", func(c *gin.Context) {
- file, err := c.FormFile("file")
- })
- engine.Run()
调用gin.Context的SaveUploadedFile()方法可以将文件保存到某个目录下:
- dst := "./uploads/" + file.Filename
- c.SaveUploadedFile(file,"./uploadFile")
Go默认文件上传缓冲区为32M,当有大量文件上传时,服务器内存的压力会很大,因此可以通过MaxMultipartMemory属性来设置缓冲区大小:
- //8M
- engine.MaxMultipartMemory = 8 << 20
上传文件时,不限制文件大小可以会导致服务存储空间暴涨,因为有必须限制上传文件大小:
- fileMaxSize := 4 << 20 //4M
- if int(file.Size) > fileMaxSize {
- c.String(http.StatusBadRequest, "文件不允许大小于4M")
- return
- }
对文件类型,也可以进行限制:
- reader, err := file.Open()
- if err != nil {
- fmt.Println(err)
- return
- }
- b := make([]byte, 512)
- reader.Read(b)
-
- contentType := http.DetectContentType(b)
- if contentType != "image/jpeg" && contentType != "image/png" {
- c.String(http.StatusOK, "文件格式错误")
- return
- }
在上面的代码中,我们读取文件的前512个字节,再调用http.DetectContentType()便可以获取文件的MIME值。
- package main
-
- import (
- "fmt"
- "log"
- "net/http"
-
- "github.com/gin-gonic/gin"
- )
-
- func main() {
- engine := gin.Default()
- //8M
- engine.MaxMultipartMemory = 8 << 20
- engine.POST("/upload", func(c *gin.Context) {
- file, err := c.FormFile("file")
- if err != nil {
- log.Println(err)
- c.String(http.StatusBadRequest, "文件上传失败")
- return
- }
- fileMaxSize := 4 << 20 //4M
- if int(file.Size) > fileMaxSize {
- c.String(http.StatusBadRequest, "文件不允许大小于32KB")
- return
- }
-
- reader, err := file.Open()
- if err != nil {
- fmt.Println(err)
- return
- }
- b := make([]byte, 512)
- reader.Read(b)
-
- contentType := http.DetectContentType(b)
- if contentType != "image/jpeg" && contentType != "image/png" {
- c.String(http.StatusOK, "文件格式错误")
- return
- }
-
- dst := "./uploads/" + file.Filename
- c.SaveUploadedFile(file, dst)
- c.String(http.StatusOK, fmt.Sprintf("'%s' 上传成功!", file.Filename))
- })
- engine.Run()
- }
-
- $ curl -F "file=@./1.jpg" -X POST "http://localhost:8080/upload"
- '1.jpg' 上传成功!
如果要上传多个文件,多次调用gin.Context的FormFile()方法也是可以的,但更好的方式是使用gin.Context的MultipartForm()方法:
- package main
-
- import (
- "fmt"
- "log"
- "net/http"
-
- "github.com/gin-gonic/gin"
- )
-
- func main() {
- engine := gin.Default()
- engine.POST("/uploadMul", func(c *gin.Context) {
- form, err := c.MultipartForm()
- if err != nil {
- log.Println(err)
- c.String(http.StatusBadRequest, "文件上传失败")
- return
- }
- files := form.File["upload"]
- for _, file := range files {
- fmt.Println(file.Filename)
- }
- c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
- })
- engine.Run()
- }
运行程序后,使用curl命令上传多个文件:
- $ curl -F "upload=@./1.jpg" -F "upload=@./2.jpg" -X POST "http://localhost:8080/uploadMul
- 2 files uploaded
Go标准库net/http对文件上传已经提供了非常完善的支持,可以满足我们大部分需求,Gin框架在其基础做了封装,让我们使用起来更加方便迅速。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。