目录
  • 前言
  • 文件上传
    • 表单操作
    • 服务端操作
  • 流程实现
    • 小结

      前言

      最近在写一个文件上传的功能,现在来进行整理总结一下go语言如何上传文件的,本文主要分享一下golang实现文件上传的流程和具体代码,供大家参考,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

      文件上传

      表单操作

      要使表单能够上传文件,需要添加form的enctype属性enctype="multipart/form-data",upload.html代码如下:

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

      服务端操作

      在服务端启动一个服务,并添加一个handlerFunc并完善相关功能即可:

      package main
      
      import (
      	"fmt"
      	"html/template"
      	"io"
      	"log"
      	"net/http"
      	"os"
      )
      
      func main()  {  
      	http.HandleFunc("/upload", Upload) 
      	if err := http.ListenAndServe("127.0.0.1:9090", nil); err != nil {
      		log.Fatal(err)
      	}
      
      }
      
      func Upload(w http.ResponseWriter, r *http.Request)  {
      	//判断请求方式
      	if r.Method == "POST" {
      		//设置内存大小
      		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("./upload", os.ModePerm)
      		//创建上传文件
      		f, err := os.Create("./upload/" + handler.Filename)
      		if err != nil {
      			fmt.Println(err)
      			return
      		}
      		defer f.Close()
      		io.Copy(f, file)
      		w.WriteHeader(http.StatusCreated)
      		io.WriteString(w, "Uploaded successfully")
      	} else {
      		//渲染页面 解析模板文件
      		tpl, _ := template.ParseFiles("./upload.html")
      		tpl.Execute(w, nil)
      	}
      }

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

      GO语言实现文件上传的示例代码

      选择文件之后就会在当前目录下的upload文件夹中看到上传的文件了。

      流程实现

      通过上面的示例可以看到,处理文件上传我们需要先调用FormFile,FormFile返回提供的表单键的第一个文件, 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
      }

      在FormFile方法中,会调用r.ParseMultipartForm, 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
      }

      里面的参数表示maxMemory,调用ParseMultipartForm之后,ParseMultipartForm将请求主体解析为multipart / form-data。解析整个请求体,将上传的文件部分存储在maxMemory大小的内存里面,如果文件大小超过了maxMemory,那么剩下的部分将存储在系统的临时文件中。我们可以通过r.FormFile获取上面的文件句柄,然后实例中使用了io.Copy来存储文件。

      小结

      文件上传主要有以下三步:

      • 表单中增加enctype属性
      • 服务端调用r.ParseMultipartForm,把上传的文件存储在内存和临时文件中
      • 使用r.FormFile获取文件句柄,然后对文件进行存储等处理。
      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。