This is a creation in Article, where the information may have evolved or changed.
First of all recommend a book go in practice, through a super small and very practical case to enhance Golang internal strength.
In technique incrementally saving a file , the reader is told how to handle multiple files at the same time to submit the processing method
The following code is slightly different from the article:
Func uploadbigfile (w http. Responsewriter, R *http. Request) {MR, ERR: = R.multipartreader () if err! = Nil {fmt. SPRINTLN (Err) fmt. Fprintln (W, err) return} values: = Make (map[string][]string, 0) Maxvaluebytes: = Int64 (<< 20) For {part, err: = Mr. Nextpart () If err = = Io. EOF {Break} Name: = part. FormName () if name = = "" {continue} FileName: = part. FileName () var b bytes. Buffer if FileName = = "" {n, err: = Io. Copyn (&b, part, maxvaluebytes) if err! = Nil && Err! = Io. EOF {fmt. SPRINTLN (Err) fmt. Fprintln (W, err) return} maxvaluebytes-= N if maxvaluebytes <= 0 { Msg: = "multipart message too large" FMT. Fprint (W, msg) return} Values[name] = append (Values[name], b.string ()) } DST, err: = OS. Create ("/tmp/upload/" + fileName) defer DST. Close () for {buffer: = Do ([]byte, 100000) cbytes, err: = part. Read (buffer) If err = = Io. EOF {break} DST. Write (Buffer[0:cbytes])}}}
When conducting the benchmark test, it is found that the above method is faster than normal processing when handling a single file upload.
Normal file Upload processing interface
func upload(w http.ResponseWriter, r *http.Request) { file, head, err := r.FormFile("my_file") if err != nil { fmt.Sprintln(err) fmt.Fprintln(w, err) return } localFileDir := "/tmp/upload/" err = os.MkdirAll(localFileDir, 0777) if err != nil { fmt.Sprintln(err) fmt.Fprintln(w, err) return } localFilePath := localFileDir + head.Filename localFile, err := os.Create(localFilePath) if err != nil { fmt.Sprintln(err) fmt.Fprintln(w, err) return } defer localFile.Close() io.Copy(localFile, file) fmt.Fprintln(w, localFilePath)}
Benchmark Test Code
Func benchmarkupload (b *testing. B) {for i: = 0; i < B.N; i++ {path: = "/home/kes/code_1.13.1-1497464373_amd64.deb" file, err: = OS.O Pen (PATH) if err! = Nil {b.error (ERR)} defer file. Close () Body: = &bytes. buffer{} Writer: = multipart. Newwriter (body) part, err: = writer. Createformfile ("My_file", filepath. Base (path)) If err! = Nil {b.error (err)} io. Copy (part, file) writer. Close () Req: = Httptest. Newrequest ("POST", "/upload", body) req. Header.set ("Content-type", writer. Formdatacontenttype ()) Res: = Httptest. Newrecorder () Upload (res, req) if Res. Code! = http. Statusok {b.error ("not")}}//T.Log (res. Body.string ())//T.Log (Io.read)}func Benchmarkuploadbig (b *testing. B) {for i: = 0; i < B.N; i++ {path: = "/home/kes/code_1.13.1-1497464373_amd64.deb" file, err: = OS.O Pen (path) IF Err! = Nil {b.error (ERR)} defer file. Close () Body: = &bytes. buffer{} Writer: = multipart. Newwriter (body) part, err: = writer. Createformfile ("My_file", filepath. Base (path)) If err! = Nil {b.error (err)} io. Copy (part, file) writer. Close () Req: = Httptest. Newrequest ("POST", "/upload", body) req. Header.set ("Content-type", writer. Formdatacontenttype ()) Res: = Httptest. Newrecorder () Uploadbigfile (res, req) if Res. Code! = http. Statusok {b.error ("not")}}//T.Log (res. Body.string ())//T.Log (Io.read)}
The file size of the test is about 44M
Test results
$ go test -bench="." -vBenchmarkUpload-4 1 1074491528 ns/opBenchmarkUploadBig-4 2 517001745 ns/opPASSok _/home/kes/test 2.966s$ go test -bench="." -vBenchmarkUpload-4 1 1295672144 ns/opBenchmarkUploadBig-4 2 537212487 ns/opPASSok _/home/kes/test 3.218s