#4.5处理文件上传 你想处理一个由用户上传的文件。例如,你正在建设一个类似Instagram 的网站,所以需要处理和存储用户提供的照片。我们该如何处理呢? 文件要能够上传,首先第一步就是要修改form的`enctype`属性,`enctype`属性有如下三种情况: application/x-www-form-urlencoded 表示在发送前编码所有字符(默认) multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。 text/plain 空格转换为 "+" 加号,但不对特殊字符编码。 我们如果要使得文件能够上传,那么我们的html应该如下所示 上传文件
我们增加一个handlerFunc如下: http.HandleFunc("/upload", upload) // upload func upload(w http.ResponseWriter, r *http.Request) { fmt.Println("method:", r.Method) //获取请求的方法 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("file") if err != nil { fmt.Println(err) } defer file.Close() fmt.Fprintf(w, "%v", handler.Header) f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { panic(err) } defer f.Close() io.Copy(f, file) } } 通过上面的代码我们可以看到,文件上传我们需要调用`r.ParseMultipartForm`,里面的参数表示maxMemory,调用`ParseMultipartForm`之后我们上传的文件存储在设置的那么大的内存里面,如果文件大小超过了这个内存,那么剩下的部分存储在系统的临时文件中。我们可以通过`r.FormFile`获取上面的文件句柄,然后实例中使用了`io.Copy`来存储文件。 >获取其他非文件字段信息的时候就不需要调用`r.ParseForm`,因为在需要的时候Go自动会去调用。而且`ParseMultipartForm`调用一次之后,后面再次调用不会再有效果。 通过上面的实例我们可以看到我们上传文件主要三步处理: - 1、表单中增加enctype="multipart/form-data" - 2、服务端调用`r.ParseMultipartForm`,把上传的文件存储在内存和临时文件中 - 3、使用`r.FormFile`获取文件句柄,然后对文件进行存储等处理。 文件handler是multipart.FileHeader,里面存储了如下结构信息 type FileHeader struct { Filename string Header textproto.MIMEHeader // contains filtered or unexported fields } 我们通过上面的实例代码打印出来上传文件的信息如下 ![](images/4.5.upload2.png?raw=true) ## links * [目录]() * 上一节: [防止多次递交表单](<4.4.md>) * 下一节: [小结](<4.6.md>) ## LastModified * $Id$