Files
build-web-application-with-…/4.5.md
2012-09-07 16:27:15 +08:00

87 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#4.5处理文件上传
你想处理一个由用户上传的文件。例如你正在建设一个类似Instagram 的网站,所以需要处理和存储用户提供的照片。我们该如何处理呢?
文件要能够上传首先第一步就是要修改form的`enctype`属性,`enctype`属性有如下三种情况:
application/x-www-form-urlencoded 表示在发送前编码所有字符(默认)
multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain 空格转换为 "+" 加号,但不对特殊字符编码。
我们如果要使得文件能够上传那么我们的html应该如下所示
<html>
<head>
<title>上传文件</title>
</head>
<body>
<form enctype="multipart/form-data" action="http://127.0.0.1:9090/upload" method="post">
<input type="file" name="file" />
<input type="hidden" name="token" value="{{.}}">
<input type="submit" value="upload" />
</form>
</body>
</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
* [目录](<preface.md>)
* 上一节: [防止多次递交表单](<4.4.md>)
* 下一节: [小结](<4.6.md>)
## LastModified
* $Id$