golang io.Reader和io.Writer

Reader和Writer

type Reader interface {
    Read(p []byte) (n int, err error)
}

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

实现reader和writer的模块:
在这里插入图片描述

围绕io.Reader/Writer,有几个常用的实现:

net.Conn, os.Stdin, os.File: 网络、标准输入输出、文件的流读取

strings.Reader: 把字符串抽象成Reader

bytes.Reader: 把[]byte抽象成Reader

bytes.Buffer: 把[]byte抽象成Reader和Writer

bufio.Reader/Writer: 抽象成带缓冲的流读取(比如按行读写)

bufio

bufio就是在系统io中间多了一个缓冲区,
在这里插入图片描述

以buferio为例,来看具体的实现:
1 读-将一个string.newreader读到*bufio
2 写-先定义一个bytes.newbuffer,再构造成bufio.newwriter,再调用write/writestring方法写入byte/string

package main

import (
	"bytes"
	"fmt"
	// "os"
	"strings"
	"bufio"
)

//type Reader struct { ... }

// NewReaderSize 将 rd 封装成一个带缓存的 bufio.Reader 对象,
// 缓存大小由 size 指定(如果小于 16 则会被设置为 16)。
// 如果 rd 的基类型就是有足够缓存的 bufio.Reader 类型,则直接将
// rd 转换为基类型返回。
//func NewReaderSize(rd io.Reader, size int) *Reader

// NewReader 相当于 NewReaderSize(rd, 4096)
//func NewReader(rd io.Reader) *Reader

// bufio.Reader 实现了如下接口:
// io.Reader
// io.WriterTo
// io.ByteScanner
// io.RuneScanner

func testRead(){
	s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
	br := bufio.NewReader(s)

	buf:=make([]byte,1024)//sliece
	n, err := br.Read(buf)


	// buf:= [512]byte{}//array
	// n, err := br.Read(buf[:])//将array切片

	fmt.Printf("%s %v %v\n", buf[:n], n, err) // ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 36 <nil>
}

func testReadstring(){
	s := strings.NewReader("亲爱的提奥,梵高")
	br := bufio.NewReader(s)
   // ReadString 在 br 中查找 delim 并返回 delim 及其之前的所有数据。
   // func (b *Reader) ReadString(delim byte) (line []byte, err error)

	n, err := br.ReadString(',')
	fmt.Printf("%s  %v\n", n, err) // 亲爱的提奥,  <nil>

	// 如果未找到 delim 且遇到错误(通常是 io.EOF),则返回缓存中的所
	n, err = br.ReadString(',')
	fmt.Printf("%s  %v\n", n, err) // 梵高  EOF
	fmt.Println(n)
	fmt.Println(string(n))

}

func TestReadBytes() {
	// ReadBytes 功能同 ReadSlice,只不过返回的是缓存的拷贝。
	// func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
	s := strings.NewReader("ABC,你好啊,HIJ")
	br := bufio.NewReader(s)
	line, err := br.ReadBytes(',')
	if err != nil {
	   panic(err)
	} 
	fmt.Printf("%s  %v\n", line, err) //
	line, err = br.ReadBytes(',')
	if err != nil {
	   panic(err)
	} 
	fmt.Printf("%s  %v\n", line, err) //
	fmt.Println(line)
	fmt.Println(string(line))


}
// ReadLine 是一个低水平的行读取原语,大多数情况下,应该使用
// ReadBytes('\n') 或 ReadString('\n'),或者使用一个 Scanner。
//
// ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片。用于
// 读取一行数据,不包括行尾标记(\n 或 \r\n)。
//
// 只要能读出数据,err 就为 nil。如果没有数据可读,则 isPrefix 返回
// false,err 返回 io.EOF。
//
// 如果找到行尾标记,则返回查找结果,isPrefix 返回 false。
// 如果未找到行尾标记,则:
// 1、缓存不满,则将缓存填满后再次查找。
// 2、缓存是满的,则返回整个缓存,isPrefix 返回 true。
//
// 整个数据尾部“有一个换行标记”和“没有换行标记”的读取结果是一样。
//
// 如果 ReadLine 读取到换行标记,则调用 UnreadByte 撤销的是换行标记,
// 而不是返回的数据。
func testReadline(){
	s := strings.NewReader("ABC,你好啊,HIJ,李银河")
	br := bufio.NewReader(s)
	var finish bool	
	line,finish ,err := br.ReadLine()
	if err != nil {
	   panic(err)
	} 
	fmt.Println(line,finish)
	fmt.Println(string(line))
}



//type Writer struct { ... }

// NewWriterSize 将 wr 封装成一个带缓存的 bufio.Writer 对象,
// 缓存大小由 size 指定(如果小于 4096 则会被设置为 4096)。
// 如果 wr 的基类型就是有足够缓存的 bufio.Writer 类型,则直接将
// wr 转换为基类型返回。
//func NewWriterSize(wr io.Writer, size int) *Writer

// NewWriter 相当于 NewWriterSize(wr, 4096)
//func NewWriter(wr io.Writer) *Writer

//func NewWriter(wr io.Writer) *Writer

// bufio.Writer 实现了如下接口:
// io.Writer
// io.ReaderFrom
// io.ByteWriter

// WriteString 功能同 Write,只不过写入的是字符串
// func (b *Writer) WriteString(s string) (int, error)

// WriteRune 向 b 写入 r 的 UTF-8 编码,返回 r 的编码长度。
// func (b *Writer) WriteRune(r rune) (size int, err error)

// Flush 将缓存中的数据提交到底层的 io.Writer 中
// func (b *Writer) Flush() error

// Available 返回缓存中未使用的空间的长度
// func (b *Writer) Available() int

// Buffered 返回缓存中未提交的数据的长度
// func (b *Writer) Buffered() int

// Reset 将 b 的底层 Writer 重新指定为 w,同时丢弃缓存中的所有数据,复位
// 所有标记和错误信息。相当于创建了一个新的 bufio.Writer。
// func (b *Writer) Reset(w io.Writer)

func TestWriteTo() {
	// WriteTo方法实现了io.WriterTo接口。
	// func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
	s := strings.NewReader("李银河")
	br := bufio.NewReader(s)
	b := bytes.NewBuffer(make([]byte, 0))
	br.WriteTo(b)
	fmt.Println(b)
	fmt.Printf("%T\n",b)
	fmt.Println(b.String())
} 




func TestNewWriter() {
 
	// NewWriter创建一个具有默认大小缓冲、写入w的*Writer。
	// 相当于 NewWriterSize(wr, 4096)
	// func NewWriter(w io.Writer) *Writer
  
	// Buffered()返回缓冲中已使用的字节数。
	// func (b *Writer) Buffered() int
  
	// Available()返回缓冲中还有多少字节未使用。
	// func (b *Writer) Available() int
  
	// Reset丢弃缓冲中的数据,清除任何错误,将b重设为将其输出写入w。
	// func (b *Writer) Reset(w io.Writer)
  
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
  
	fmt.Println(bw.Available(), bw.Buffered()) // 4096  0
	bw.WriteString("card")
	fmt.Println(bw.Available(), bw.Buffered()) // 4092  4
  
	bw.Reset(b)
	fmt.Println(bw.Available(), bw.Buffered()) // 4096  0
	fmt.Println(bw)

}


func TestWriteString() {
	// WriteString 同 Write,只不过写入的是字符串
	// func (b *Writer) WriteString(s string) (int, error)
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
	bw.WriteString("hello world")
	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
	fmt.Printf("%s\n", b)
} 

func TestWritebytes() {
	// WriteString 同 Write,只不过写入的是字符串
	// func (b *Writer) WriteString(s string) (int, error)
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
	bw.WriteByte('h')
	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
	fmt.Printf("%s\n", b)
} 
func TestWriterune() {
	// WriteString 同 Write,只不过写入的是字符串
	// func (b *Writer) WriteString(s string) (int, error)
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
	bw.WriteRune('h')
	bw.Flush()//y一定要flush到底层//y一定要flush到底层//y一定要flush到底层
	fmt.Printf("%s\n", b)
} 



func TestReadFrom() {
	// ReadFrom实现了io.ReaderFrom接口。
	//将r读到b
	// func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
	// ReadFrom无需使用Flush
	// b := bytes.NewBuffer(make([]byte, 0))
	b :=bytes.NewBufferString("你好啊")
	s := strings.NewReader(",李银河")
	bw := bufio.NewWriter(b)
	bw.ReadFrom(s)
	fmt.Println(b)
} 


 
func TestReadWriter() {
	// ReadWriter类型保管了指向Reader和Writer类型的指针
	// 实现了io.ReadWriter接口。
  
	// NewReadWriter 生成bufio.ReadWriter对象
	// func NewReadWriter(r *Reader, w *Writer) *ReadWriter
	b := bytes.NewBuffer(make([]byte, 0))
	bw := bufio.NewWriter(b)
	s := strings.NewReader("hello world")
	br := bufio.NewReader(s)
	rw := bufio.NewReadWriter(br, bw)
  
	word, err := rw.ReadString(' ')
	if err != nil {
	   panic(err)
	}
	fmt.Printf("%s\n", word) // hello
  
	_, err = rw.WriteString(",I'm coming")
	if err != nil {
	   panic(err)
	}
	rw.Flush()
	fmt.Println(b)
}



func TestNewScanner()  {
	// Scanner 提供了一个方便的接口来读取数据,例如遍历多行文本中的行。Scan 方法会通过
	// 一个“匹配函数”读取数据中符合要求的部分,跳过不符合要求的部分。“匹配函数”由调
	// 用者指定。本包中提供的匹配函数有“行匹配函数”、“字节匹配函数”、“字符匹配函数”
	// 和“单词匹配函数”,用户也可以自定义“匹配函数”。默认的“匹配函数”为“行匹配函
	// 数”,用于获取数据中的一行内容(不包括行尾标记)
	//
	// Scanner 使用了缓存,所以匹配部分的长度不能超出缓存的容量。默认缓存容量为 4096 -
	// bufio.MaxScanTokenSize,用户可以通过 Buffer 方法指定自定义缓存及其最大容量。
	//
	// Scan 在遇到下面的情况时会终止扫描并返回 false(扫描一旦终止,将无法再继续):
	// 1、遇到 io.EOF
	// 2、遇到读写错误
	// 3、“匹配部分”的长度超过了缓存的长度
	//
	// 如果需要对错误进行更多的控制,
	// 或“匹配部分”超出缓存容量,或需要连续扫描,
	// 则应该使用 bufio.Reader
	// func NewScanner(r io.Reader) *Scanner
  
	// Bytes方法返回最近一次Scan调用生成的token。
	// 底层数组指向的数据可能会被下一次Scan的调用重写。
	// func (s *Scanner) Bytes() []byte
  
  
	// Buffer()方法设置扫描时使用的初始缓冲区和最大值
	// 默认情况下,Scan使用内部缓冲区并设置MaxScanTokenSize的最大令牌大小
	s := strings.NewReader("周起\n卡牌\n程序员\n")
	bs := bufio.NewScanner(s)
	bs.Buffer(make([]byte,0),bufio.MaxScanTokenSize)
	for bs.Scan() {
	   // 周起
	   // 卡牌
	   // 程序员
	   fmt.Printf("%s\n", bs.Bytes())
	}
 
}

func TestScan()  {
	// Scan方法获取当前位置的token(该token可以通过Bytes或Text方法获得),
	// 并让Scanner的扫描位置移动到下一个token。
	// 当扫描因为抵达输入流结尾或者遇到错误而停止时,
	// 本方法会返回false。在Scan方法返回false后,
	// Err方法将返回扫描时遇到的任何错误;
	// 除非是io.EOF,此时Err会返回nil。
	// func (s *Scanner) Scan() bool
	s := strings.NewReader("周起 卡牌 程序员")
	bs := bufio.NewScanner(s)
	bs.Split(bufio.ScanWords)
	for bs.Scan()  {
	   fmt.Printf("%s %s\n", bs.Text(), bs.Bytes())
	}
} 

  
 func TestScanBytes()  {
	// Bytes方法返回最近一次Scan调用生成的token。
	// 底层数组指向的数据可能会被下一次Scan的调用重写。
	s := strings.NewReader("abcd")
	bs := bufio.NewScanner(s)
	bs.Split(bufio.ScanBytes)
	for bs.Scan(){
	   // a
	   // b
	   // c
	   // d
	   fmt.Printf("%s\n", bs.Bytes())
	}
 }
  
 func TestScanRunes()  {
	// ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),
	// 本函数会将每个utf-8编码的unicode码值作为一个token返回。
	s := strings.NewReader("周起卡牌程序员")
	bs := bufio.NewScanner(s)
	bs.Split(bufio.ScanRunes)
	for bs.Scan()  {
	   // 周
	   // 起
	   // 卡
	   // 牌
	   // 程
	   // 序
	   // 员
	   fmt.Printf("%s\n", bs.Text())
	}
 }
  
 func TestScanWords()  {
	// ScanRunes是用于Scanner类型的分割函数(符合SplitFunc),
	// 本函数会将空白(参见unicode.IsSpace)
	// 分隔的片段(去掉前后空白后)作为一个token返回。
	// 本函数永远不会返回空字符串。
	s := strings.NewReader("我 是 卡 牌")
	bs := bufio.NewScanner(s)
	bs.Split(bufio.ScanWords)
	for bs.Scan(){
	   // 我
	   // 是
	   // 卡
	   // 牌
	   fmt.Printf("%s\n", bs.Text())
	}
 }
  
 func TestScanLines()  {
	// 将每一行文本去掉末尾的换行标记作为一个token返回
	// 此函数的bs.Scan()的默认值
	s := strings.NewReader("卡牌\n周起\n程序员\n")
	bs := bufio.NewScanner(s)
	bs.Split(bufio.ScanLines)
	for bs.Scan(){
	   // 卡牌
	   // 周起
	   // 程序员
	   fmt.Printf("%s\n", bs.Text())
	}
} 

func main(){
	testRead()
	testReadstring()
	TestReadBytes()
	testReadline()
	TestWriteTo() 
	TestWriteString()
	TestWritebytes()
	TestWriterune()
	TestReadFrom()
	TestScan()
	TestNewScanner() 
	TestScanBytes()
	TestScanWords()
	TestScanRunes()
	TestScanLines()
}

代码参考:https://blog.csdn.net/weixin_46742102/article/details/107937096

buffer

先看buffer结构体

// type Buffer struct {
// 	buf      []byte //  byte切片  contents are the bytes buf[off : len(buf)]
// 	off      int    //  偏移量,read中记录已读入的位置,write中记录写入的位置
// 	lastRead readOp //  记录最后读入的位置 
// }

new方法:

// func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// func NewBufferString(s string) *Buffer {
// 	return &Buffer{buf: []byte(s)}
// }

buffer:
1 读 从b读到p,先将b new成buffer,定义一个[]]byte类型的p
2 写 将一个[]byte写到*bufferr

//func (b *Buffer) Read(p []byte) (n int, err error)
//从b读到p,先将b new成buffer,定义一个[]]byte类型的p
package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"
)
func main() {
	Newbuffer()
	Readrune()
	// Readfrombuffer()
	// Readstrings()
	Readbyte()
	ReadNext()
	// Writetobuffer()

}

// type Buffer struct {
// 	buf      []byte //  byte切片  contents are the bytes buf[off : len(buf)]
// 	off      int    //  偏移量,read中记录已读入的位置,write中记录写入的位置
// 	lastRead readOp //  记录最后读入的位置 
// }


// func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }

// func NewBufferString(s string) *Buffer {
// 	return &Buffer{buf: []byte(s)}
// }

func Newbuffer() {
	//bytes.buffer
	buf1 := bytes.NewBufferString("hello")
	buf2 := bytes.NewBuffer([]byte("hello"))
	buf3 := bytes.NewBuffer([]byte{'h', 'e', 'l', 'l', 'o'})
	// 以上三者等效,输出//hello
	buf4 := bytes.NewBufferString("")
	buf5 := bytes.NewBuffer([]byte{})
	// 以上两者等效,输出//""
	fmt.Println(buf1,buf1.String(), buf2, buf3, buf4, buf5, 1)
	fmt.Printf("%T\n",buf2)

}

//func (b *Buffer) Read(p []byte) (n int, err error)
//从b读到p,先将b new成buffer,定义一个[]]byte类型的p
func Readfrombuffer(){
	s1 := []byte("hello")
	buff := bytes.NewBuffer(s1)
	s2 := []byte(" world")
	buff.Write(s2)
	fmt.Println(buff.String()) //hello world
	
	s3 := make([]byte,3)
	buff.Read(s3)     //把buff的内容读入到s3,s3的容量为3,读了3个过来
	fmt.Println(buff.String()) //lo world
	fmt.Println(string(s3))   //hel
	buff.Read(s3) //继续读入3个,原来的被覆盖
	
	fmt.Println(buff.String())     //world
	fmt.Println(string(s3))    //"lo "
}

func Readbyte(){
	buf := bytes.NewBufferString("hello")
	fmt.Println(buf.String())
	for i :=0;i<buf.Len();i++ {
		b,_ := buf.ReadByte()   //取出第一个byte,赋值给b
		fmt.Println(buf.String()) //ello
		fmt.Printf("取出了%s\n",string(b))  //h
	}
}

func Readrune(){//int32,相当于java的char
	buf6 := bytes.NewBufferString("你好啊李银河hello")
	fmt.Println(buf6.String())//你好啊李银河hello
	fmt.Println(buf6.Len()) //23   3*6+5
	for i :=0;i<buf6.Len();i++ {
		b,n,_ := buf6.ReadRune()  //取出第一个rune
		fmt.Println(string(b))  //你
		fmt.Println(n)   //3,"你“作为utf8存储占3个byte
	}
	fmt.Println(buf6.String())
}

func Readbytes()  {
	var d byte = ','  //分隔符
	buf := bytes.NewBufferString("你好,charlie,pretty ,boy")
	fmt.Println(buf.String()) //你好esmieth
	for {
		b,_ := buf.ReadBytes(d)  //读到分隔符,并返回给b
		if strings.Compare(string(b),"")==0{//读到""后返回结束循坏
			return
		}
	fmt.Println(string(b)) //你好e
	}
}

func ReadNext()  {
	buf := bytes.NewBufferString("你好,charlie,pretty ,boy")
	fmt.Println(buf.String()) //你好esmieth
	for{
		b:= buf.Next(3)  //读取3字节返回给b
		if strings.Compare(string(b),"")==0{//读到""后返回结束循坏,一定要设置返回条件
			return
		}
		fmt.Println(string(b)) //你好e
	}
}


func Readstrings(){
	var d byte = ','
	buf := bytes.NewBufferString("你好,smieth,and,lucy")
	fmt.Println(buf.String())  //你好esmieth
	for {
		b,_:= buf.ReadString(d) 
		if strings.Compare(string(b),"")==0{//读到""后返回结束循坏
			return
		}  //读取到分隔符,并返回给b
		fmt.Println(string(b))
		 //你好e
	}
}

// 读取文件
func Readfromfile(){
	file, _ := os.Open("text.txt")
	buf := bytes.NewBufferString("")
	for {
		n,_:=buf.ReadFrom(file)
		if n==0{
			return
		}
		fmt.Println(buf.String())
	}
}




func Writetobuffer() {
	//write string to buffer
	s0 := " charlie"
	buf0 := bytes.NewBufferString("hello")
	fmt.Println(buf0.String())    //hello
	buf0.WriteString(s0)           //将string写入到buf的尾部
	fmt.Println(buf0.String())    //hello charlie

	//write []byte to buffer
	s := []byte("world")
	buf := bytes.NewBufferString("hello") 
	fmt.Println(buf.String())    //hello
	buf.Write(s)                 //将s这个slice添加到buf的尾部
	fmt.Println(buf.String())   //hello world

	//write byte to buffer
	var s1 byte = 'w'//byte:字符
	buf1 := bytes.NewBufferString("hello ") 
	fmt.Println(s1) //把buf的内容转换为string,hello
	buf1.WriteByte(s1)         //将s写到buf的尾部
	fmt.Println(buf1) //hello?
}

func Writefrombuffer(){
	file,_ := os.Create("text.txt")
		// for i:=0;i<50;i++{
			buf2 := bytes.NewBufferString("hello world,my name is charlie Wong\n")
			buf2.WriteTo(file)//func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
		// }
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值