It's a common requirement that extact N bytes must be read or written. For example, TCP framing almost always needs this guarantee. POSIX read()/write() don't have this feature and programmers have to develop their own readN() / writeN() functions.
To make developers' life easier, Golang standard library provide this feature for free. But the patterns for READN and WRITEN are not consistent.
For WRITEN, the io.Writer interface itself ensures.
For READN, the io.ReadFull() must be used.
0 TLDR;
io.Writer.Write(buf) itself guarantees len(buf) bytes successfully written if it returns a nil error.
io.Reader.Read(buf) doesn't ensure len(buf) bytes read even if it returns a nil error.
1 Write(buf) is enough
type Writer ¶
Writer is the interface that wraps the basic Write method.
Write writes len(p) bytes from p to the underlying data stream. It returns the number of bytes written from p (0 <= n <= len(p)) and any error encountered that caused the write to stop early. Write must return a non-nil error if it returns n < len(p). Write must not modify the slice data, even temporarily.
Implementations must not retain p.
if _, err := conn.Write(buf); err != nil {
// when err != nil, n must be less than len(buf)
log.Fatal(err)
}
// if nil error returned, len(buf) bytes written is ensured
2 Read(buf) is NOT enough
type Reader ¶
Reader is the interface that wraps the basic Read method.
Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may use all of p as scratch space during the call. If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.
When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF.
Callers should always process the n > 0 bytes returned before considering the error err. Doing so correctly handles I/O errors that happen after reading some bytes and also both of the allowed EOF behaviors.
If len(p) == 0, Read should always return n == 0. It may return a non-nil error if some error condition is known, such as EOF.
Implementations of Read are discouraged from returning a zero byte count with a nil error, except when len(p) == 0. Callers should treat a return of 0 and nil as indicating that nothing happened; in particular it does not indicate EOF.
Implementations must not retain p.
3 So we have io.ReadFull()
func ReadFull ¶
ReadFull reads exactly len(buf) bytes from r into buf. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading some but not all the bytes, ReadFull returns ErrUnexpectedEOF. On return, n == len(buf) if and only if err == nil. If r returns an error having read at least len(buf) bytes, the error is dropped.
if _, err := io.ReadFull(r, buf); err != nil {
// when err != nil, n must be less than len(buf)
log.Fatal(err)
}
// if nil error returned, len(buf) bytes read is ensured
No comments:
Post a Comment