前言

输入输出(I/O)是一个程序最基础的一部分。而Golang中涉及io的包非常多,对于小白很容易混淆,现在就来花一点时间来把梳理清楚。

本文将主要涉及以下的几个包

ioio.ioutilbufiobytesstringsnetos

标准库的区别

首先需要从高层次上来区分开这几个包。在官网Standard library · std · pkg.go.dev中,这几个包的区别和侧重点如下

ioio.ioutilbufiobytesbytes.Readerbytes.Bufferstringsstring.Readernetnet.connReaderWriterosos.File os.Stdio os.Stdout os.StderrReaderWriter
io

io库是GO语言中的核心,其中定义了IO操作中的相关接口。

io.Readerio.Writer

在io中最基础的就是, 这两个的接口如下:

type Reader interface {
	Read(p []byte) (n int, err error) //接收一个字节切片p,将读取的数据放入到p中,返回读取了的字节个数
}

type Writer interface {
	Write(p []byte) (n int, err error) //接收一个字节切片p,将p中的数据写入到文件或文件中,返回写入了的字节个数
}

这俩个接口定义了最基本的读与写。

io.Seekerio.Closer
io.Seekerio.Closer
type Seeker interface {
	Seek(offset int64, whence int) (int64, error) // 设置相对于whence偏移offset的读或者写的偏移量,返回相对于文件开始的新偏移量和一个错误
}

type Closer interface {
	Close() error  //关闭数据流
}
io.ReaderAtio.WriterAt
io.ReaderAtio.WriterAtio.Readerio.Writer
type ReaderAt interface {
    ReadAt(p []byte, off int64) (n int, err error) //从基本输入源的偏移量 off 处开始,将 len(p) 个字节读取到 p 中,它返回读取的字节数 n(0 <= n <= len(p))以及任何遇到的错误。
}

type WriterAt interface {
    WriteAt(p []byte, off int64) (n int, err error) //从 p 中将 len(p) 个字节写入到偏移量 off 处的基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误
}
io.ReaderFromio.WiterTo
io.ReaderFromio.WriterToio.Readerio.Writer
type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error) //从 r 中读取数据,直到 EOF 或发生错误。其返回值 n 为读取的字节数
}

type WriterTo interface {
    WriteTo(w Writer) (n int64, err error) //将数据写入 w 中,直到没有数据可写或发生错误。其返回值 n 为写入的字节数
}
适配:各种数据类型的读取与写入

io库中也针对byte、Rune,string类型的数据实现了各自的Reader和Writer

Byte 读写一个字节
type ByteReader interface {
    ReadByte() (c byte, err error) //读一个字节
}

type ByteWriter interface {
    WriteByte(c byte) error       //写一个字节
}

type ByteScanner interface {
    ByteReader                    // 内嵌了 ByteReader 接口
    UnreadByte() error            // 将上一次 ReadByte 的字节还原
}
Rune 读一个字符
type RuneReader interface {
	ReadRune() (r rune, size int, err error) //读一个字符r 返回尺寸size 和错误
}

type RuneScanner interface {
	RuneReader
	UnreadRune() error
}

注意:没有RuneWriter接口,据说是开发者认为几乎不需要RuneWriter接口

String 写入一个字符串
type StringWriter interface {
	WriteString(s string) (n int, err error) //字符串s的内容写到w
}
组合:各式各样的接口搭配

上面的都是一些单一的接口,而有些时候同时需要莫两个或者三个的接口的所有功能,所以在io库中提供了这些“小接口”组合而成的“大接口”。

总结:io库中的所有接口概要图

以上的接口可以归纳为下图

实现:接口的各种实现场景
io
bufioosnetstringsbytes
附:io库中的一些变量与方法

除了接口,io库中还有相对应的一些变量、方法和接口实现(后续讲)。

显示各种错误的变量

io库中的变量主要是一些错误。

EOFErrClosePipeErrNoProgressErrShortBufferErrShortWriteErrUnexpectedEOF
各种相关操作方法
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)func Pipe() (*PipeReader, *PipeWriter)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)func WriteString(w Writer, s string) (n int, err error)
io.ioutil
io.ioutil
NopCloser(r io.Reader) io.ReadCloserReadAll(r io.Reader) ([]byte, error)ReadDir(dirname string) ([]os.FileInfo, error)ReadFile(filename string) ([]byte, error)TempDir(dir, prefix string) (name string, err error)TempFile(dir, prefix string) (f *os.File, err error)WriteFile(filename string, data []byte, perm os.FileMode) error
bufio
疑问:缓冲的作用
bufioio

这是因为在一些很小的写入和读取时,很耗费io。 这时可以把这些小片段的数据放在缓冲中,然后再统一读取或写入,这样可以大大的提高效率。

实现:Reader读取器
bufioio
bufio.Reader结构体
type Reader struct {
	buf          []byte    // 缓冲区,为字节切片
	rd           io.Reader // reader 由 client 提供
	r, w         int       // 缓冲区读写的位置
	err          error
	lastByte     int // UnreadByte的最后读取的字节;-1表示无效
	lastRuneSize int // UnreadRune最后读取的字符大小;-1表示无效
}

bufio.Reader创建
const (
	defaultBufSize = 4096  //默认大小
)

const minReadBufferSize = 16 //最小尺寸

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 { //minReadBufferSize==16
        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()NewReaderSize()bufio.ReaderNewReader()NewReaderSize()NewReaderSize()
bufio.Reader的方法及接口实现
Buffered()intDiscard(n int) (discarded int, err error)Peek(n int) ([]byte, error)Read(p []byte) (n int, err error)io.ReaderReadByte() (byte, error)io.ByteReaderReadBytes(delim byte) ([]byte, error)ReadLine() (line []byte, isPrefix bool, err error)ReadRune() (r rune, size int, err error)ReadSlice(delim byte) (line []byte, err error)ReadString(delim byte) (string, error)Reset(r io.Reader)Size() intUnreadByte() errorUnreadRune() errorWriteTo(w io.Writer) (n int64, err error)io.WriterTo

在这里插入图片描述

实现:Writer写入器
bufio.writer结构体
type Writer struct {
	err error      //错误
	buf []byte     //缓冲区
	n   int
	wr  io.Writer
}

bufio.Writer创建
func NewWriterSize(w io.Writer, size int) *Writer {
	// Is it already a Writer?
	b, ok := w.(*Writer)
	if ok && len(b.buf) >= size {
		return b
	}
	if size <= 0 {
		size = defaultBufSize
	}
	return &Writer{
		buf: make([]byte, size),
		wr:  w,
	}
}

func NewWriter(w io.Writer) *Writer {
	return NewWriterSize(w, defaultBufSize)
}
bufio.Readerbufio.WriterNewWriterNewWriterSize
bufio.Writer方法及接口实现
Available() intBuffered() intFlush() errorReadFrom(r io.Reader) (n int64, err error)io.ReaderFromReset(w io.Writer)Size() intWrite(p []byte) (nn int, err error)io.WriterWriteByte(c byte) errorio.ByteWriterWriteRune(r rune) (size int, err error)WriteString(s string) (int, error)io.StringWriter

在这里插入图片描述

附:Scanner扫描仪

扫描器模块的主要作用是把数据流分割成一个个标记并除去它们之间的空格

bufio.Scanner结构体
type Scanner struct {
	r            io.Reader // 由client提供的reader.
	split        SplitFunc // 分隔标记的函数.
	maxTokenSize int       // 标记的最大尺寸
	token        []byte    // 由split返回的最后一个token
	buf          []byte    // 用作分割参数的缓冲区
	start        int       // buf中第一个未处理的字节
	end          int       // 缓冲区内的数据结束
	err          error     // 错误
	empties      int       // 连续的空标记的数量
	scanCalled   bool      // 扫描已被调用;缓冲区正在使用中
	done         bool      // 扫描已完成
}

bufio.Scanner创建
const (
	MaxScanTokenSize = 64 * 1024

	startBufSize = 4096 // Size of initial allocation for buffer.
)


func NewScanner(r io.Reader) *Scanner {
	return &Scanner{
		r:            r,                    
		split:        ScanLines,          //默认函数
		maxTokenSize: MaxScanTokenSize,   //64*4096
	}
}
bufio.Scanner的方法
Buffer(buf []byte, max int)Bytes() []byteErr() errorScan() boolSplit(split SplitFunc)Text() string

os
os
实现:os.File
os.File结构体
type File struct {
	*file // os specific
}

/*file_unix.go*/
type file struct {
	pfd         poll.FD
	name        string   // 名称
	dirinfo     *dirInfo // nil unless directory being read
	nonblock    bool     // whether we set nonblocking mode
	stdoutOrErr bool     // whether this is stdout or stderr
	appendMode  bool     // whether file is opened for appending
}

可以看到由于不同的操作系统的文件实现方式不一致,所以因操作系统而各异。
在这里插入图片描述

os.File的创建
/*file_unix.go*/ 
// 给定文件描述符fd和文件名 返回一个新的文件
func NewFile(fd uintptr, name string) *File {
	kind := kindNewFile
	if nb, err := unix.IsNonblock(int(fd)); err == nil && nb {
		kind = kindNonBlock
	}
	return newFile(fd, name, kind)
} 
os.File的方法和接口实现
Create(name string) (*File, error)CreateTemp(dir, pattern string) (*File, error)Open(name string) (*File, error)OpenFile(name string, flag int, perm FileMode) (*File, error)
Chdir() errorChmod(mode FileMode) errorChown(uid, gid int) errorClose() errorFd() uintptrName() stringRead(b []byte) (n int, err error) | |ReadAt(b []byte, off int64) (n int, err error)io.ReaderAtReadDir(n int) ([]DirEntry, error)ReadFrom(r io.Reader) (n int64, err error)io.ReaderFromReaddir(n int) ([]FileInfo, error)Readdirnames(n int) (names []string, err error)Seek(offset int64, whence int) (ret int64, err error)io.SeekerSetDeadline(t time.Time) errorSetReadDeadline(t time.Time) errorSetWriteDeadline(t time.Time) errorStat() (FileInfo, error)Sync() errorSyscallConn() (syscall.RawConn, error)Truncate(size int64) errorWrite(b []byte) (n int, err error)io.WriterWriteAt(b []byte, off int64) (n int, err error)io.WriterAtWriteString(s string) (n int, err error)io.StringWriter

实现: 其实就是文件的stdin,stdout,stderr

而对于标准输入输出stdin,stdout,stderr它们其实就是指定的File。

var (
	Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
	Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
	Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
net
实现:Conn接口与conn实现
net.Conn接口

在net库中,定义了底层的接口Conn。

type Conn interface {
	Read(b []byte) (n int, err error)
	Write(b []byte) (n int, err error)
	Close() error
	LocalAddr() Addr
	RemoteAddr() Addr
	SetDeadline(t time.Time) error
	SetReadDeadline(t time.Time) error
	SetWriteDeadline(t time.Time) error
}
net.conn结构体

同时也实现了一个接口类型conn

type conn struct {
	fd *netFD
}
net.conn接口实现
Read(b []byte) (n int, err error)io.ReaderWrite(b []byte) (n int, err error)io.WriterClose() errorio.Closer

strings
实现:strings.Reader

对字符串进行功效处理,在strings里面有一个Reader数据结构。

string.Reader结构体
type Reader struct {
	s        string  //字符串
	i        int64   // 当前读取下标
	prevRune int     // 先前读取字符的下标
}

string.Reader方法及接口实现
Len() intRead(b []byte) (n int, err error)io.ReaderReadAt(b []byte, off int64) (n int, err error)io.ReaderAReadByte() (byte, error)io.ByteReaderReadRune() (ch rune, size int, err error)io.RuneReaderReset(s string)Seek(offset int64, whence int) (int64, error)io.SeekerSize() int64UnreadByte() errorio.RuneScannerWriteTo(w io.Writer) (n int64, err error)io.WriterTo

在这里插入图片描述

bytes
实现:bytes.Reader
stringsbyte
实现:bytes.Buffer
bytes.Buffer
bytes.Buffer结构体
type Buffer struct {
	buf      []byte // 缓冲区 内容为buf[off : len(buf)]
	off      int    //  读在 &buf[off], 写在 &buf[len(buf)]
	lastRead readOp // 上一次读的操作
}

bytes.Buffer方法与接口实现
Bytes() []byteCap() intGrow(n int)Len() intNext(n int) []byteRead(b []byte) (n int, err error)io.ReaderReadByte() (byte, error)io.ByteReaderReadFrom(r io.Reader) (n int64, err error)io.ReaderFromReadBytes(delim byte) (line []byte, err error)ReadRune() (ch rune, size int, err error)io.RuneReaderReadString(delim byte) (line string, err error)Reset(s string)string() stringTruncate(n int)UnreadByte() errorio.ByteScannerUnreadRune() errorio.RuneScannerWrite(p []byte) (n int, err error)io.WriterWriteByte(c byte) errorio.ByteWriterWriteRune(r rune) (n int, err error)WriteString(s string) (n int, err error)io.StringWriterWriteTo(w io.Writer) (n int64, err error)io.WriterTo

总结 来个SUMMARY

ioioio.ioutiliobufioosnetstringsbytes

在这里插入图片描述