我们在对文件进行io操作的时候,经常看到需要我们传递一个 io.reader 或者 io.writer 对象作为读写的入参, 那么我们该如何或者这些个rw对象呢? 其实很简单,你只需要查找一下哪些对象实现了 read或者 writer方法,那么你只需要创建一个实现了这2个方法之一的对象 , 那他就可以是一个 io.reader 或者 io.writer 。
当然最常见的应该就是我们的 os.file对象了, 另外还有 bufio.reader, bytes.buffer 等对象都可以作为io的rw入参。
当然你也可以自己定义一个对象,实现 io.reader 或者 io.writer 接口中定义的方法,那么你的对象也可以作为一个rw入参来使用了。 这个也就是go语言中面向接口编程的完美体现。
go中reader writer接口定义
type reader interface { read(p []byte) (n int, err error) } type writer interface { write(p []byte) (n int, err error) }
os.file对象中的rw实现代码
// read reads up to len(b) bytes from the file and stores them in b. // it returns the number of bytes read and any error encountered. // at end of file, read returns 0, io.eof. func (f *file) read(b []byte) (n int, err error) { if err := f.checkvalid("read"); err != nil { return 0, err } n, e := f.read(b) return n, f.wraperr("read", e) } // write writes len(b) bytes from b to the file. // it returns the number of bytes written and an error, if any. // write returns a non-nil error when n != len(b). func (f *file) write(b []byte) (n int, err error) { if err := f.checkvalid("write"); err != nil { return 0, err } n, e := f.write(b) if n < 0 { n = 0 } if n != len(b) { err = io.errshortwrite } epipecheck(f, e) if e != nil { err = f.wraperr("write", e) } return n, err }
bufio.reader中的rw实现代码
// read reads data into p. // it returns the number of bytes read into p. // the bytes are taken from at most one read on the underlying reader, // hence n may be less than len(p). // to read exactly len(p) bytes, use io.readfull(b, p). // if the underlying reader can return a non-zero count with io.eof, // then this read method can do so as well; see the [io.reader] docs. func (b *reader) read(p []byte) (n int, err error) { n = len(p) if n == 0 { if b.buffered() > 0 { return 0, nil } return 0, b.readerr() } if b.r == b.w { if b.err != nil { return 0, b.readerr() } if len(p) >= len(b.buf) { // large read, empty buffer. // read directly into p to avoid copy. n, b.err = b.rd.read(p) if n < 0 { panic(errnegativeread) } if n > 0 { b.lastbyte = int(p[n-1]) b.lastrunesize = -1 } return n, b.readerr() } // one read. // do not use b.fill, which will loop. b.r = 0 b.w = 0 n, b.err = b.rd.read(b.buf) if n < 0 { panic(errnegativeread) } if n == 0 { return 0, b.readerr() } b.w = n } // copy as much as we can // note: if the slice panics here, it is probably because // the underlying reader returned a bad count. see issue 49795. n = copy(p, b.buf[b.r:b.w]) b.r = n b.lastbyte = int(b.buf[b.r-1]) b.lastrunesize = -1 return n, nil } // writebuf writes the reader's buffer to the writer. func (b *reader) writebuf(w io.writer) (int64, error) { n, err := w.write(b.buf[b.r:b.w]) if n < 0 { panic(errnegativewrite) } b.r = n return int64(n), err }
bytes.buffer中的rw实现代码
// read reads the next len(p) bytes from the buffer or until the buffer // is drained. the return value n is the number of bytes read. if the // buffer has no data to return, err is io.eof (unless len(p) is zero); // otherwise it is nil. func (b *buffer) read(p []byte) (n int, err error) { b.lastread = opinvalid if b.empty() { // buffer is empty, reset to recover space. b.reset() if len(p) == 0 { return 0, nil } return 0, io.eof } n = copy(p, b.buf[b.off:]) b.off = n if n > 0 { b.lastread = opread } return n, nil } // write appends the contents of p to the buffer, growing the buffer as // needed. the return value n is the length of p; err is always nil. if the // buffer becomes too large, write will panic with errtoolarge. func (b *buffer) write(p []byte) (n int, err error) { b.lastread = opinvalid m, ok := b.trygrowbyreslice(len(p)) if !ok { m = b.grow(len(p)) } return copy(b.buf[m:], p), nil }
注意这些方法一般是绑定在指针类型的对象上, 所以你在创建你需要的rw对象的时候需要使用&指针符号或者使用 new函数来创建对象, 如:w := &bytes.buffer{} 等效于 w := new(bytes.buffer)