An end-of-file indicator signals that no more data can be read from a file or stream. In Go, io.EOF commonly marks normal completion: a reader returns it when iteration reaches the end, so the loop can stop rather than treat the condition as a failure. section 10.2.6
Distinguish the end-of-input signal from other read outcomes:
- Handle io.EOF as the expected stopping condition when a reader has no more parts or bytes to provide. section 10.2.6
- Handle an unexpected end separately with io.ErrUnexpectedEOF when incomplete input is an error rather than a normal boundary. section 7.1.1
- Choose sequential reading for large or streamed data instead of loading an entire file into memory with os.ReadFile. section 7.1.1
Stopping a multipart parser
A multipart upload handler repeatedly calls mr.NextPart(). When the request contains no more parts, the call returns io.EOF; the handler breaks from the loop and proceeds without treating normal completion as an upload error. section 10.2.6
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 complete loop that retrieves multipart parts, tests for io.EOF, and exits when the request body is exhausted. section 10.2.6

