Golang-上傳-and-接收-檔案

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
package mainimport (    "fmt"    "io"    "net/http"    "log")// 擷取大小的借口type Sizer interface {    Size() int64}// hello world, the web serverfunc HelloServer(w http.ResponseWriter, r *http.Request) {    if "POST" == r.Method {    file, _, err := r.FormFile("userfile")    if err != nil {        http.Error(w, err.Error(), 500)        return    }    defer file.Close()    f,err:=os.Create("filenametosaveas")    defer f.Close()    io.Copy(f,file)fmt.Fprintf(w, "上傳檔案的大小為: %d", file.(Sizer).Size())    return    }    // 上傳頁面    w.Header().Add("Content-Type", "text/html")    w.WriteHeader(200)    html := `<form enctype="multipart/form-data" action="/hello" method="POST">    Send this file: <input name="userfile" type="file" />    <input type="submit" value="Send File" /></form>`    io.WriteString(w, html)}func main() {    http.HandleFunc("/hello", HelloServer)    err := http.ListenAndServe(":12345", nil)    if err != nil {    log.Fatal("ListenAndServe: ", err)    }}用戶端上傳檔案代碼: func Upload() (err error) {    // Create buffer    buf := new(bytes.Buffer) // caveat IMO dont use this for large files, \    // create a tmpfile and assemble your multipart from there (not tested)    w := multipart.NewWriter(buf)    // Create file field    fw, err := w.CreateFormFile("file", "helloworld.go") //這裡的file很重要,必須和伺服器端的FormFile一致    if err != nil {    fmt.Println("c")    return err    }    fd, err := os.Open("helloworld.go")    if err != nil {    fmt.Println("d")    return err    }    defer fd.Close()    // Write file field from file to upload    _, err = io.Copy(fw, fd)    if err != nil {    fmt.Println("e")    return err    }    // Important if you do not close the multipart writer you will not have a    // terminating boundry    w.Close()    req, err := http.NewRequest("POST","http://192.168.2.127/configure.go?portId=2", buf)    if err != nil {    fmt.Println("f")    return err    }    req.Header.Set("Content-Type", w.FormDataContentType())      var client http.Client    res, err := client.Do(req)    if err != nil {    fmt.Println("g")    return err    }    io.Copy(os.Stderr, res.Body) // Replace this with Status.Code check    fmt.Println("h")    return err}

處理檔案上傳

你想處理一個由使用者上傳的檔案,比如你正在建設一個類似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="uploadfile" /> <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("uploadfile")        if err != nil {            fmt.Println(err)            return        }        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 {            fmt.Println(err)            return        }        defer f.Close()        io.Copy(f, file)    }}

通過上面的代碼可以看到,處理檔案上傳我們需要調用r.ParseMultipartForm

裡面的參數表示maxMemory,調用ParseMultipartForm之後,

上傳的檔案儲存體在maxMemory大小的記憶體裡面,如果檔案大小超過了maxMemory,那麼剩下的部分將儲存在系統的臨時檔案中。

我們可以通過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 stringHeader   textproto.MIMEHeader// contains filtered or unexported fields}

我們通過上面的執行個體代碼列印出來上傳檔案的資訊如下

![](images/4.5.upload2.png?raw=true)

列印檔案上傳後伺服器端接受的資訊

用戶端上傳檔案

我們上面的例子示範了如何通過表單上傳檔案,然後在伺服器端處理檔案,

其實Go支援類比用戶端表單功能支援檔案上傳,詳細用法請看如下樣本:

package mainimport ("bytes""fmt""io""io/ioutil""mime/multipart""net/http""os")func postFile(filename string, targetUrl string) error {    bodyBuf := &bytes.Buffer{}    bodyWriter := multipart.NewWriter(bodyBuf)    //關鍵的一步操作    fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)    if err != nil {        fmt.Println("error writing to buffer")        return err    }    //開啟檔案控制代碼操作    fh, err := os.Open(filename)    if err != nil {        fmt.Println("error opening file")        return err    }    //iocopy    _, err = io.Copy(fileWriter, fh)    if err != nil {        return err    }    contentType := bodyWriter.FormDataContentType()    bodyWriter.Close()    resp, err := http.Post(targetUrl, contentType, bodyBuf)    if err != nil {        return err    }    defer resp.Body.Close()    resp_body, err := ioutil.ReadAll(resp.Body)    if err != nil {        return err    }    fmt.Println(resp.Status)    fmt.Println(string(resp_body))    return nil}// sample usagefunc main() {    target_url := "http://localhost:9090/upload"    filename := "./astaxie.pdf"    postFile(filename, target_url)}

上面的例子詳細展示了用戶端如何向伺服器上傳一個檔案的例子,

用戶端通過multipart.Write把檔案的文字資料流寫入一個緩衝中,然後調用http的Post方法把緩衝傳到伺服器。

如果你還有其他普通欄位例如username之類的需要同時寫入,那麼可以調用multipart的WriteField方法寫很多其他類似的欄位。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.