Go标准库学习:io库

发布时间 2023-12-20 16:43:57作者: 流云cpp

io库

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


常量(Constants)

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

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

变量(Variables)

var EOF = errors.New("EOF")

表示读到了文件结尾。

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

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

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

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

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

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

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

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

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

接口 (interfaces)

读取和写入

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

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相关的接口

// 从偏移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相关的接口,包括:从某个位置读写、从其他流读出或写入、定位流、关闭等。

组合接口成为新接口

// 同时支持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)

拷贝

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.

读取

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

func Pipe() (*PipeReader, *PipeWriter)

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

PipeReader

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

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

其他

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

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

生成接口类型的函数

func NopCloser(r Reader) ReadCloser

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

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

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

func MultiWriter(writers ...Writer) Writer

MultiWriter类似。

结构 (Structures)

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结构。

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()在指定偏移进行写入,该方法不受位置影响,都是从初始位置开始计算偏移。

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