介绍
Go 语言标准库 io
提供 I/O
原语的基本接口。所谓 I/O
,顾名思义 input
和 output
,即数据输入和输出。
本文我们通过阅读源码介绍 golang 语言标准库 io
,限于篇幅,我们以介绍 io.Reader
接口为例。
标准库 io 的接口类型 Reader
我们阅读一下标准库 io
的 Reader
源码:
Reader 源码:
type Reader interface { Read(p []byte) (n int, err error) }
阅读源码,我们可以发现标准库 io
的 Reader
接口包含一个函数 Read(p []byte) (n int, err error)
。
在 Go 语言中,任意类型实现某一接口中的所有方法,即代表该类型实现了该接口。
所以,任意实现 Read(p []byte) (n int, err error)
的类型,即代表实现了 io.Reader
接口。
03
标准库中io.Reader
的实现类型
在 Golang 标准库 strings、bytes、bufio、和 os 中,都有实现 io.Reader
的类型。
标准库 strings
标准库 strings
的 Reader
类型,实现了标准库 io
的 Reader
接口,源码:
type Reader struct { s string i int64 // current reading index prevRune int // index of previous rune; or < 0 } // 省略代码 ... func (r *Reader) Read(b []byte) (n int, err error) { if r.i >= int64(len(r.s)) { return 0, io.EOF } r.prevRune = -1 n = copy(b, r.s[r.i:]) r.i += int64(n) return }
阅读源码,我们可以发现 strings.Reader
实现了 Read(b []byte) (n int, err error)
,即代表实现了 io.Reader
接口。
使用 strings
包提供的 NewReader
函数,可以创建一个 strings.Reader
类型的变量。
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
示例:
r := strings.NewReader("some io.Reader stream to be read\n") if _, err := io.Copy(os.Stdout, r); err != nil { log.Fatal(err) }
输出:
some io.Reader stream to be read
标准库 bytes
标准库 bytes
的 Reader
类型,也实现了标准库 io
的 Reader
接口,源码:
type Reader struct { s []byte i int64 // current reading index prevRune int // index of previous rune; or < 0 } // 省略代码 ... // Read implements the io.Reader interface. func (r *Reader) Read(b []byte) (n int, err error) { if r.i >= int64(len(r.s)) { return 0, io.EOF } r.prevRune = -1 n = copy(b, r.s[r.i:]) r.i += int64(n) return }
阅读源码,我们可以发现 bytes.Reader
实现了 Read(b []byte) (n int, err error)
,即代表实现了 io.Reader
接口。
使用 bytes
包提供的 NewReader
函数,可以创建一个 bytes.Reader
类型的变量。
// NewReader returns a new Reader reading from b. func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
示例:
r := bytes.NewReader([]byte("some io.Reader stream to be read")) if _, err := io.Copy(os.Stdout, r); err != nil { log.Fatal(err) }
输出:
some io.Reader stream to be read
标准库 bufio
标准库 bufio
的函数 NewReader
,创建一个新的其缓冲区 Reader.buf
有默认大小的 *Reader
,源码:
const ( defaultBufSize = 4096 ) // 省略代码 ... // Reader implements buffering for an io.Reader object. type Reader struct { buf []byte rd io.Reader // reader provided by the client r, w int // buf read and write positions err error lastByte int // last byte read for UnreadByte; -1 means invalid lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid } // 省略代码 ... func NewReaderSize(rd io.Reader, size int) *Reader { // Is it already a Reader? b, ok := rd.(*Reader) if ok && len(b.buf) >= size { return b } if size < minReadBufferSize { size = minReadBufferSize } r := new(Reader) r.reset(make([]byte, size), rd) return r } // NewReader returns a new Reader whose buffer has the default size. func NewReader(rd io.Reader) *Reader { return NewReaderSize(rd, defaultBufSize) }
阅读源码,我们可以发现函数 NewReader
创建一个新的其缓冲区 Reader.buf
有默认大小的 *Reader
。
示例:
rd := strings.NewReader("some io.Reader stream to be read") r := bufio.NewReader(rd) if _, err := io.Copy(os.Stdout, r); err != nil { log.Fatal(err) }
输出:
some io.Reader stream to be read
标准库 os
标准库 os
的 os.File
类型,也实现了标准库 io
的 Reader
接口,源码:
// File represents an open file descriptor. type File struct { *file // os specific } // 省略代码 ... // Read reads up to len(b) bytes from the File. // 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) }
阅读源码,我们可以发现 os.File
实现了 Read(b []byte) (n int, err error)
,即代表实现了 io.Reader
接口。
使用 os
包提供的 Open
函数,可以创建一个 os.File
类型的变量。
func Open(name string) (*File, error) { return OpenFile(name, O_RDONLY, 0) }
示例:
f, _ := os.Open("service.log") if _, err := io.Copy(os.Stdout, f); err != nil { log.Fatal(err) }
输出:
some io.Reader stream to be read
04
总结
Go 语言标准库 io
提供 I/O
原语的基本接口。在 Go 语言标准库 strings、bytes、bufio、和 os 中,都有实现 io.Reader
的类型。
本文我们介绍了在 Go 语言标准库中实现 io.Reader
的类型的源码,及简单的使用示例。
建议感兴趣的读者朋友们,继续阅读 Go 语言标准库中实现 io.Writer
和 io.Closer
的类型的源码,并思考其使用场景。
通过阅读标准库 io
的代码,不仅可以熟悉标准库 io
的使用方式,还可以更加深入理解 golang 中接口的使用方式。
推荐阅读: