io库

io中包括了常用的io流中的函数,并依靠这些函数定义了常用的接口和接口组合。我觉得这是最重要的。


每篇一首歌

常量(Constants)

1
2
3
4
5
const (
SeekStart = 0 // 定位到文件头
SeekCurrent = 1 // 定位到当前读写的位置
SeekEnd = 2 // 定位到文件尾
)

都是用于在文件读写时进行定位的常量,相当于C库中的SEEK_STARTSEEK_SETSEEK_END

变量(Variables)

1
var EOF = errors.New("EOF")

表示读到了文件结尾。

需要注意的是,返回EOF时只能直接返回io库中定义的这个变量,因为在进行EOF的判断时,会直接将返回的error和EOF进行比较(==)。

1
var ErrClosedPipe = errors.New("io: read/write on closed pipe")

在关闭了的Pipe上进行了读或者写

1
var ErrNoProgress = errors.New("multiple Read calls return no data or error")

一个Reader被多个调用方调用,通常意味着该Reader损坏了。

1
var ErrShortWrite = errors.New("short write")

读取到了少于请求的数量的字节,但又返回不了一个明确的错误。

1
var ErrUnexpectedEOF = errors.New("unexpected EOF")

当读取一个固定长度的数据块或者一个结构时,读到中间读到了意料之外的EOF。

接口 (interfaces)

读取和写入

io库中定义了很多常用的接口,涉及输入输出的类都应当遵循这些接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Reader interface {
Read(p []byte) (n int, err error)
}

type Writer interface {
Write(p []byte) (n int, err error)
}

type ByteReader interface {
ReadByte() (byte, error)
}

type ByteWriter interface {
WriteByte(c byte) error
}

// 读出一个Rune,返回该码点和该码点的字节长度
type RuneReader interface {
ReadRune() (r rune, size int, err error)
}

最常用的就是读写函数,分别是ReaderWriter,分别读取和写入slice字节,并返回读取和写入的字节数。

类似的是ByteReaderByteWriter,分别读取和写入一个字节。RuneReader读出一个unicode码点,但没有RuneWriter

其他IO相关的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 从偏移off处读取len(p)字节至p。返回读取的字节或者发生的错误。0 <= n <= len(p)
// 1. n < len(p)时,函数会返回一个非nil的err,解释为什么只读取了n个字节。
// 如果可用的数据不足len(p),ReadAt会阻塞,直到读完了或者发生了错误。
// 2. 如果n == len(p),返回的err == nil 或者err == io.EOF
// 如果这个函数在某个支持Seek的结构体内,Seek设置的偏移不应该影响本函数。
type ReaderAt interface {
ReadAt(p []byte, off int64) (n int, err error)
}

// 将数据写入到w中(使用Writer的Write()方法)
type WriterTo interface {
WriteTo(w Writer) (n int64, err error)
}

// 从r中读取数据(使用Reader的Read()方法)
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}

// 将写一个String
type StringWriter interface {
WriteString(s string) (n int, err error)
}

// 在off写数据
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}

// 在指定位置进行读或者写
// offset是一个有符号整数,whence有三个可选值:io.SeekStart, io.SeekCurrent, io.SeekEnd
type Seeker interface {
Seek(offset int64, whence int) (int64, error)
}

// 关闭输入输出流
type Closer interface {
Close() error
}

这部分是其他的IO相关的接口,包括:从某个位置读写、从其他流读出或写入、定位流、关闭等。

组合接口成为新接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 同时支持ReadByte()和UnreadByte()
type ByteScanner interface {
ByteReader
UnreadByte() error
}

// 同时支持ReadRune()和UnreadRune()
type RuneScanner interface {
RuneReader
UnreadRune() error
}

// 同时有Read和Close
type ReadCloser interface {
Reader
Closer
}

// 同时有Read、Seek
type ReadSeeker interface {
Reader
Seeker
}

// 同时有Read、Seek和Close
type ReadSeekCloser interface {
Reader
Seeker
Closer
}

// 同时有Read和Write
type ReadWriter interface {
Reader
Writer
}

// 同时有Read、Write和Seek
type ReadWriteSeeker interface {
Reader
Writer
Seeker
}

// 同时有Read、Write和Close
type ReadWriteCloser interface {
Reader
Writer
Closer
}

这部分主要是将各个单一函数的接口进行组合(或者扩展)。

函数 (Functions)

拷贝

1
2
3
func Copy(dst Writer, src Reader) (written int64, err error)
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

将数据从src写入到dst。如果dst支持ReadFrom的话则使用该API。

需要注意的是,如果拷贝成功的话,返回的err == nil,而不是io.EOF.

读取

1
2
3
func ReadAll(r Reader) ([]byte, error)
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
func ReadFull(r Reader, buf []byte) (n int, err error)

读取功能。

Pipe

1
func Pipe() (*PipeReader, *PipeWriter)

对应于Linux中的pipe接口,创建一个输入流和输出流,写到输出流中的数据可以从输入流中读出。

PipeReader
1
2
3
4
5
6
7
type PipeReader struct {
// contains filtered or unexported fields
}

func (r *PipeReader) Close() error
func (r *PipeReader) CloseWithError(err error) error
func (r *PipeReader) Read(data []byte) (n int, err error)

可以读取、关闭、关闭并给Writer返回一个错误。

Close()后如果另一端再写会返回io.ErrClosedPipe. 而CloseWithError后如果另一端再写会返回传入的err。

Read()时如果另一端关闭了则会返回io.EOF.

PipeWriter
1
2
3
4
5
6
7
type PipeWriter struct {
// contains filtered or unexported fields
}

func (w *PipeWriter) Close() error
func (w *PipeWriter) CloseWithError(err error) error
func (w *PipeWriter) Write(data []byte) (n int, err error)

PipeReader有着类似的函数,只不过当写端调用Close()时,对应的Reader端读取时返回io.EOF

其他

1
func WriteString(w Writer, s string) (n int, err error)

有StringWriter了还要有个内置的WriteString函数,看来写字符串很常用啊。

生成接口类型的函数

1
func NopCloser(r Reader) ReadCloser

生成一个ReaderCloser,该ReaderCloserRead()方法来自传入的ReaderClose()方法是一个nop(没有操作)。

1
2
func MultiReader(readers ...Reader) Reader
func TeeReader(r Reader, w Writer) Reader

MultiReader将多个Reader组合,读取时前一个Reader到了EOF就继续从下一个Reader读。

1
func MultiWriter(writers ...Writer) Writer

MultiWriter类似。

结构 (Structures)

1
2
3
4
5
6
type LimitedReader struct {
R Reader // underlying reader
N int64 // max bytes remaining
}
func LimitReader(r Reader, n int64) Reader
func (l *LimitedReader) Read(p []byte) (n int, err error)

限制最多读取N个字节。LimitReader()生成一个新的LimitReader结构。

1
2
3
4
5
6
7
8
9
type OffsetWriter struct {
// contains filtered or unexported fields
}

func NewOffsetWriter(w WriterAt, off int64) *OffsetWriter

func (o *OffsetWriter) Seek(offset int64, whence int) (int64, error)
func (o *OffsetWriter) Write(p []byte) (n int, err error)
func (o *OffsetWriter) WriteAt(p []byte, off int64) (n int, err error)

OffsetWriter能够从指定的偏移处进行写。

NewOffsetWriter()创建一个新的OffsetWriter

Seek()设置偏移;Write()进行写入;WriteAt()在指定偏移进行写入,该方法不受位置影响,都是从初始位置开始计算偏移。

1
2
3
4
5
6
7
8
9
type SectionReader struct {
// contains filtered or unexported fields
}

func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
func (s *SectionReader) Read(p []byte) (n int, err error)
func (s *SectionReader) ReadAt(p []byte, off int64) (n int, err error)
func (s *SectionReader) Seek(offset int64, whence int) (int64, error)
func (s *SectionReader) Size() int64

roff开始读取,最多读n个就到EOF