A file upload transfers a local file to a Go web server through a multipart form. The request combines binary file data with metadata such as the filename and may also contain ordinary text fields. section 10.0 section 10.2.3
A basic form uses POST, enctype="multipart/form-data", and a file input. The handler retrieves the upload with Request.FormFile, closes the returned file, creates a destination, and copies the data with io.Copy. section 10.2.3
For large or concurrent uploads, avoid ParseMultipartForm when temporary server storage would become a bottleneck. Request.MultipartReader exposes the incoming stream so the handler can process each part incrementally and pass data to its final destination. section 10.2.6
Single-file upload
A form submits a selected file to the root endpoint; the handler reads the file and metadata with r.FormFile("file"), creates /tmp/<filename>, and copies the upload into it.
Listing 10.15 Saving uploaded files incrementally
func fileForm(w http.ResponseWriter, r *http.Request) { #1
if r.Method == "GET" { #2
t, _ :=
template.ParseFiles("file_plus.html")
t.Execute(w, nil)
} else {
mr, err := r.MultipartReader() #3
if err != nil {
panic("Failed to read multipart
message")
}
values := make(map[string][]string) #4
maxValueBytes := int64(10 << 20) #5
for { #6
part, err := mr.NextPart() #7
if err == io.EOF { #7
break #7
} #7
name := part.FormName() #8
if name == "" { #8
continue #8
} #8
filename := part.FileName() #9
var b bytes.Buffer #10
if filename == "" { #11
n, err := io.CopyN(&b, part,
maxValueBytes) #12
if err != nil && err !=
io.EOF { #13
fmt.Fprint(w, "Error
processing form")
return
}
maxValueBytes -= n #14
if maxValueBytes == 0 {
msg := "multipart
message too large"
fmt.Fprint(w, msg)
return
}
values[name] = append(values
[name],b.String()) #15
continue #15
}
dst, err := os.Create("/tmp/" +
filename) #16
defer dst.Close() #17
if err != nil {
return
}
for { # #18
buffer := make([]byte, 100000)
cBytes, err :=
part.Read(buffer)
if err == io.EOF {
break
}
dst.Write(buffer[0:cBytes])
}
}
fmt.Fprint(w, "Upload complete")
}
}
Inspect the incremental multipart loop that reads parts as they arrive instead of caching a complete upload first. section 10.2.6




