GO实现文件上传操作

Serena ·
更新时间:2024-11-01
· 894 次阅读

本文实例为大家分享了GO实现文件上传操作的具体代码,供大家参考,具体内容如下

由于需求中有文件上传这一个需求,在这里我们就学习一下go语言如何上传文件。本文主要通过表单的方式进行文件上传操作。主要有以下三步:

表单中增加enctype属性

服务端调用r.ParseMultipartForm,把上传的文件存储在内存和临时文件中

使用r.FormFile获取文件句柄,然后对文件进行存储等处理。

1、表单操作

要使表单能够上传文件,首先第一步就要添加form的enctype属性进去,enctype属性有如下三种情况:

application/x-www-form-urlencoded   表示在发送前编码所有字符(默认)
multipart/form-data      不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain      空格转换为 "+" 加号,但不对特殊字符编码。

所以可以创建如下上传表单:

<html> <head>     <title>上传文件</title> </head> <body> <form enctype="multipart/form-data" action="/upload" method="post">   <input type="file" name="uploadfile" />   <input type="hidden" name="token" value="{{.}}"/>   <input type="submit" value="upload" /> </form> </body> </html>

2、服务端操作

在服务端只需要添加一个handlerFunc并完善相关功能即可:

// 处理/upload 逻辑 func upload(w http.ResponseWriter, r *http.Request) {     //获取请求的方法     fmt.Println("method:", r.Method)     //GET的处理操作     if r.Method == "GET" {         crutime := time.Now().Unix()         h := md5.New()         io.WriteString(h, strconv.FormatInt(crutime, 10))         token := fmt.Sprintf("%x", h.Sum(nil))         t, _ := template.ParseFiles("upload.gtpl")         t.Execute(w, token)     } else {         //设置内存大小         r.ParseMultipartForm(32 << 20)         //获取上传文件         file, handler, err := r.FormFile("uploadfile")         if err != nil {             fmt.Println(err)             return         }         defer file.Close()         fmt.Fprintf(w, "%v", handler.Header)         //创建上传目录         os.Mkdir("./test", os.ModePerm)         //创建上传文件         f, err := os.Create("./test/" + handler.Filename)         //f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666) // 此处假设当前目录下已存在test目录         if err != nil {             fmt.Println(err)             return         }         defer f.Close()         io.Copy(f, file)     } }

main()函数中记得添加http.HandleFunc("/upload", upload)即可。

通过http://127.0.0.1:9999/upload来测试文件上传。 截图

选择文件之后就会在当前目录下的test文件夹中成功上传文件。

3、流程解析

通过上面的代码可以看到,处理文件上传我们需要调用r.ParseMultipartForm,里面的参数表示maxMemory,调用ParseMultipartForm之后,上传的文件存储在maxMemory大小的内存里面,如果文件大小超过了maxMemory,那么剩下的部分将存储在系统的临时文件中。我们可以通过r.FormFile获取上面的文件句柄,然后实例中使用了io.Copy来存储文件。我们可以尝试使用看一下使用的相关原函数:

ParseMultipartForm函数如下:

func (r *Request) ParseMultipartForm(maxMemory int64) error {     if r.MultipartForm == multipartByReader {         return errors.New("http: multipart handled by MultipartReader")     }     if r.Form == nil {         err := r.ParseForm()         if err != nil {             return err         }     }     if r.MultipartForm != nil {         return nil     }     mr, err := r.multipartReader(false)     if err != nil {         return err     }     f, err := mr.ReadForm(maxMemory)     if err != nil {         return err     }     if r.PostForm == nil {         r.PostForm = make(url.Values)     }     for k, v := range f.Value {         r.Form[k] = append(r.Form[k], v...)         // r.PostForm should also be populated. See Issue 9305.         r.PostForm[k] = append(r.PostForm[k], v...)     }     r.MultipartForm = f     return nil }

FormFile函数如下:

func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {     if r.MultipartForm == multipartByReader {         return nil, nil, errors.New("http: multipart handled by MultipartReader")     }     if r.MultipartForm == nil {         err := r.ParseMultipartForm(defaultMaxMemory)         if err != nil {             return nil, nil, err         }     }     if r.MultipartForm != nil && r.MultipartForm.File != nil {         if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {             f, err := fhs[0].Open()             return f, fhs[0], err         }     }     return nil, nil, ErrMissingFile }

文件handlermultipart.FileHeader里面的结构体如下

// A FileHeader describes a file part of a multipart request. type FileHeader struct {     Filename string     Header   textproto.MIMEHeader     Size     int64     content []byte     tmpfile string }

4、成功结果

浏览器端显示如下消息。



GO 文件上传

需要 登录 后方可回复, 如果你还没有账号请 注册新账号