设为首页 收藏本站
查看: 1299|回复: 0

[经验分享] Golang学习 - io 包

[复制链接]

尚未签到

发表于 2018-9-19 11:59:02 | 显示全部楼层 |阅读模式
------------------------------------------------------------  

  
  先说一下接口,Go 语言中的接口很简单,在 Go 语言的 io 包中有这样一个函数:
  

  
func ReadFull(r Reader, buf []byte) (n int, err error)
  

  
  这个函数可以把对象 r 中的数据读出来,然后存入一个缓冲区 buf 中,以便其它代码可以处理 buf 中的数据。
  

  
  这里有个问题,ReadFull 函数究竟可以读取哪些对象的数据?可以读文件中的数据吗?可以读网络中的数据吗?可以读数据库中的数据吗?可以读磁盘中的扇区吗?可以读内存中的数据吗?
  

  
  答案是 ReadFull 可以读取任何对象的数据,但是有个前提,就是这个对象必须符合 Reader 的标准。
  

  
  Reader 的标准是什么呢?下面是 Reader 的定义:
  

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

  
  从上面的定义可以看出,Reader 的标准很简单,只要某个对象实现了 Read 方法,这个对象就符合了 Reader 的标准,就可以被 ReadFull 读取。
  

  
  太简单了,只需要实现 Read 方法,不需要做其它任何事情。下面我们就来定义一个自己的类型,然后实现 Read 方法:
  

  
------------------------------
  

  
// 定义一个 Ustr 类型
  
type Ustr struct {
  
s string // 数据流
  
i int    // 读写位置
  
}
  

  
// 根据字符串创建 Ustr 对象
  
func NewUstr(s string) *Ustr {
  
return &Ustr{s, 0}
  
}
  

  
// 获取未读取部分的数据长度
  
func (s *Ustr) Len() int {
  
return len(s.s) - s.i
  
}
  

  
// 实现 Ustr 类型的 Read 方法
  
func (s *Ustr) Read(p []byte) (n int, err error) {
  
for ; s.i < len(s.s) && n < len(p); s.i++ {
  
c := s.s[s.i]
  
// 将小写字母转换为大写字母,然后写入 p 中
  
if 'a'   
}
  

  
------------------------------
  

  
// RuneScanner 在 RuneReader 的基础上增加了一个 UnreadRune 方法,用于撤消最后
  
// 一次的 ReadRune 操作,以便下次的 ReadRune 操作可以读出与前一次一样的数据。
  
// UnreadRune 之前必须是 ReadRune 才能撤消成功,否则可能会返回一个错误信息(根
  
// 据不同的需求,UnreadRune 也可能返回 nil,允许随意调用 UnreadRune,但只有最
  
// 后一次的 ReadRune 可以被撤销,其它 UnreadRune 不执行任何操作)。
  
type RuneScanner interface {
  
RuneReader
  
UnreadRune() error
  
}
  

  
------------------------------
  

  
// bytes.NewBuffer 实现了很多基本的接口,可以通过 bytes 包学习接口的实现
  
func main() {
  
buf := bytes.NewBuffer([]byte("Hello World!"))
  
b := make([]byte, buf.Len())
  

  
n, err := buf.Read(b)
  
fmt.Printf("%s   %v\n", b[:n], err)
  
// Hello World!   
  

  
buf.WriteString("ABCDEFG\n")
  
buf.WriteTo(os.Stdout)
  
// ABCDEFG
  

  
n, err = buf.Write(b)
  
fmt.Printf("%d   %s   %v\n", n, buf.String(), err)
  
// 12   Hello World!   
  

  
c, err := buf.ReadByte()
  
fmt.Printf("%c   %s   %v\n", c, buf.String(), err)
  
// H   ello World!   
  

  
c, err = buf.ReadByte()
  
fmt.Printf("%c   %s   %v\n", c, buf.String(), err)
  
// e   llo World!   
  

  
err = buf.UnreadByte()
  
fmt.Printf("%s   %v\n", buf.String(), err)
  
// ello World!   
  

  
err = buf.UnreadByte()
  
fmt.Printf("%s   %v\n", buf.String(), err)
  
// ello World!   bytes.Buffer: UnreadByte: previous operation was not a read
  
}
  

  
------------------------------------------------------------
  

  
// WriteString 将字符串 s 写入到 w 中,返回写入的字节数和遇到的错误。
  
// 如果 w 实现了 WriteString 方法,则优先使用该方法将 s 写入 w 中。
  
// 否则,将 s 转换为 []byte,然后调用 w.Write 方法将数据写入 w 中。
  
func WriteString(w Writer, s string) (n int, err error)
  

  
// ReadAtLeast 从 r 中读取数据到 buf 中,要求至少读取 min 个字节。
  
// 返回读取的字节数和遇到的错误。
  
// 如果 min 超出了 buf 的容量,则 err 返回 io.ErrShortBuffer,否则:
  
// 1、读出的数据长度 == 0  ,则 err 返回 EOF。
  
// 2、读出的数据长度 <  min,则 err 返回 io.ErrUnexpectedEOF。
  
// 3、读出的数据长度 >= min,则 err 返回 nil。
  
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
  

  
// ReadFull 的功能和 ReadAtLeast 一样,只不过 min = len(buf)
  
func ReadFull(r Reader, buf []byte) (n int, err error)
  

  
// CopyN 从 src 中复制 n 个字节的数据到 dst 中,返回复制的字节数和遇到的错误。
  
// 只有当 written = n 时,err 才返回 nil。
  
// 如果 dst 实现了 ReadFrom 方法,则优先调用该方法执行复制操作。
  
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
  

  
// Copy 从 src 中复制数据到 dst 中,直到所有数据都复制完毕,返回复制的字节数和
  
// 遇到的错误。如果复制过程成功结束,则 err 返回 nil,而不是 EOF,因为 Copy 的
  
// 定义为“直到所有数据都复制完毕”,所以不会将 EOF 视为错误返回。
  
// 如果 src 实现了 WriteTo 方法,则调用 src.WriteTo(dst) 复制数据,否则
  
// 如果 dst 实现了 ReadeFrom 方法,则调用 dst.ReadeFrom(src) 复制数据
  
func Copy(dst Writer, src Reader) (written int64, err error)
  

  
// CopyBuffer 相当于 Copy,只不 Copy 在执行的过程中会创建一个临时的缓冲区来中
  
// 转数据,而 CopyBuffer 则可以单独提供一个缓冲区,让多个复制操作共用同一个缓
  
// 冲区,避免每次复制操作都创建新的缓冲区。如果 buf == nil,则 CopyBuffer 会
  
// 自动创建缓冲区。
  
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
  

  
------------------------------
  

  
// 示例:WriteString、ReadAtLeast、ReadFull
  
func main() {
  
io.WriteString(os.Stdout, "Hello World!\n")
  
// Hello World!
  

  
r := strings.NewReader("Hello World!")
  
b := make([]byte, 15)
  

  
n, err := io.ReadAtLeast(r, b, 20)
  
fmt.Printf("%q   %d   %v\n", b[:n], n, err)
  
// ""   0   short buffer
  

  
r.Seek(0, 0)
  
b = make([]byte, 15)
  

  
n, err = io.ReadFull(r, b)
  
fmt.Printf("%q   %d   %v\n", b[:n], n, err)
  
// "Hello World!"   12   unexpected EOF
  
}
  

  
------------------------------
  

  
// 示例:CopyN、Copy、CopyBuffer
  
func main() {
  
r := strings.NewReader("Hello World!")
  
buf := make([]byte, 32)
  

  
n, err := io.CopyN(os.Stdout, r, 5) // Hello
  
fmt.Printf("\n%d   %v\n\n", n, err) // 5   
  

  
r.Seek(0, 0)
  
n, err = io.Copy(os.Stdout, r)      // Hello World!
  
fmt.Printf("\n%d   %v\n\n", n, err) // 12   
  

  
r.Seek(0, 0)
  
r2 := strings.NewReader("ABCDEFG")
  
r3 := strings.NewReader("abcdefg")
  

  
n, err = io.CopyBuffer(os.Stdout, r, buf) // Hello World!
  
fmt.Printf("\n%d   %v\n", n, err)         // 12   
  

  
n, err = io.CopyBuffer(os.Stdout, r2, buf) // ABCDEFG
  
fmt.Printf("\n%d   %v\n", n, err)          // 7   
  

  
n, err = io.CopyBuffer(os.Stdout, r3, buf) // abcdefg
  
fmt.Printf("\n%d   %v\n", n, err)          // 7   
  
}
  

  
------------------------------------------------------------
  

  
// LimitReader 对 r 进行封装,使其最多只能读取 n 个字节的数据。相当于对 r 做了
  
// 一个切片 r[:n] 返回。底层实现是一个 *LimitedReader(只有一个 Read 方法)。
  
func LimitReader(r Reader, n int64) Reader
  

  
// MultiReader 将多个 Reader 封装成一个单独的 Reader,多个 Reader 会按顺序读
  
// 取,当多个 Reader 都返回 EOF 之后,单独的 Reader 才返回 EOF,否则返回读取
  
// 过程中遇到的任何错误。
  
func MultiReader(readers ...Reader) Reader
  

  
// MultiReader 将向自身写入的数据同步写入到所有 writers 中。
  
func MultiWriter(writers ...Writer) Writer
  

  
// TeeReader 对 r 进行封装,使 r 在读取数据的同时,自动向 w 中写入数据。
  
// 它是一个无缓冲的 Reader,所以对 w 的写入操作必须在 r 的 Read 操作结束
  
// 之前完成。所有写入时遇到的错误都会被作为 Read 方法的 err 返回。
  
func TeeReader(r Reader, w Writer) Reader
  

  
------------------------------
  

  
// 示例 LimitReader
  
func main() {
  
r := strings.NewReader("Hello World!")
  
lr := io.LimitReader(r, 5)
  

  
n, err := io.Copy(os.Stdout, lr)  // Hello
  
fmt.Printf("\n%d   %v\n", n, err) // 5   
  
}
  

  
------------------------------
  

  
// 示例 MultiReader
  
func main() {
  
r1 := strings.NewReader("Hello World!")
  
r2 := strings.NewReader("ABCDEFG")
  
r3 := strings.NewReader("abcdefg")
  
b := make([]byte, 15)
  
mr := io.MultiReader(r1, r2, r3)
  

  
for n, err := 0, error(nil); err == nil; {
  
n, err = mr.Read(b)
  
fmt.Printf("%q\n", b[:n])
  
}
  
// "Hello World!"
  
// "ABCDEFG"
  
// "abcdefg"
  
// ""
  

  
r1.Seek(0, 0)
  
r2.Seek(0, 0)
  
r3.Seek(0, 0)
  
mr = io.MultiReader(r1, r2, r3)
  
io.Copy(os.Stdout, mr)
  
// Hello World!ABCDEFGabcdefg
  
}
  

  
------------------------------
  

  
// 示例 MultiWriter
  
func main() {
  
r := strings.NewReader("Hello World!\n")
  
mw := io.MultiWriter(os.Stdout, os.Stdout, os.Stdout)
  

  
r.WriteTo(mw)
  
// Hello World!
  
// Hello World!
  
// Hello World!
  
}
  

  
// 示例 TeeReader
  
func main() {
  
r := strings.NewReader("Hello World!")
  
b := make([]byte, 15)
  
tr := io.TeeReader(r, os.Stdout)
  

  
n, err := tr.Read(b)                  // Hello World!
  
fmt.Printf("\n%s   %v\n", b[:n], err) // Hello World!   
  
}
  

  
------------------------------------------------------------
  

  
// NewSectionReader 对 r 进行封装,使其只能从 off 位置开始读取,最多只能读取 n
  
// 个字节的的数据。相当于对 r 做了一个切片 r[off:off+n] 返回。
  
// 底层实现是一个 *SectionReader。
  
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader
  

  
// SectionReader 实现了如下接口:
  
// io.Reader
  
// io.ReaderAt
  
// io.Seeker
  


  
//>
  
func (s *SectionReader)>  

  
------------------------------
  

  
// 示例 SectionReader
  
func main() {
  
r := strings.NewReader("Hello World!")
  
sr := io.NewSectionReader(r, 6, 5)
  

  
n, err := io.Copy(os.Stdout, sr)                  // World
  
fmt.Printf("\n%d   %d   %v\n", sr.Size(), n, err) // 5   5   
  
}
  

  
------------------------------------------------------------
  

  
// Pipe 在内存中创建一个同步管道,用于不同区域的代码之间相互传递数据。
  
// 返回的 *PipeReader 用于从管道中读取数据,*PipeWriter 用于向管道中写入数据。
  
// 管道没有缓冲区,读写操作可能会被阻塞。可以安全的对管道进行并行的读、写或关闭
  
// 操作,读写操作会依次执行,Close 会在被阻塞的 I/O 操作结束之后完成。
  
func Pipe() (*PipeReader, *PipeWriter)
  

  
// 从管道中读取数据,如果管道被关闭,则会返会一个错误信息:
  
// 1、如果写入端通过 CloseWithError 方法关闭了管道,则返回关闭时传入的错误信息。
  
// 2、如果写入端通过 Close 方法关闭了管道,则返回 io.EOF。
  
// 3、如果是读取端关闭了管道,则返回 io.ErrClosedPipe。
  
func (r *PipeReader) Read(data []byte) (n int, err error)
  

  
// 关闭管道
  
func (r *PipeReader) Close() error
  

  
// 关闭管道并传入错误信息。
  
func (r *PipeReader) CloseWithError(err error) error
  

  
// 向管道中写入数据,如果管道被关闭,则会返会一个错误信息:
  
// 1、如果读取端通过 CloseWithError 方法关闭了管道,则返回关闭时传入的错误信息。
  
// 2、如果读取端通过 Close 方法关闭了管道,则返回 io.ErrClosedPipe。
  
// 3、如果是写入端关闭了管道,则返回 io.ErrClosedPipe。
  
func (w *PipeWriter) Write(data []byte) (n int, err error)
  

  
// 关闭管道
  
func (w *PipeWriter) Close() error
  

  
// 关闭管道并传入错误信息。
  
func (w *PipeWriter) CloseWithError(err error) error
  

  
------------------------------
  

  
// 示例:管道(读取端关闭)
  
func main() {
  
r, w := io.Pipe()
  
// 启用一个例程进行读取
  
go func() {
  
buf := make([]byte, 5)
  
for n, err := 0, error(nil); err == nil; {
  
n, err = r.Read(buf)
  
r.CloseWithError(errors.New("管道被读取端关闭"))
  
fmt.Printf("读取:%d, %v, %s\n", n, err, buf[:n])
  
}
  
}()
  
// 主例程进行写入
  
n, err := w.Write([]byte("Hello World !"))
  
fmt.Printf("写入:%d, %v\n", n, err)
  
}
  

  
------------------------------
  

  
// 示例:管道(写入端关闭)
  
func main() {
  
r, w := io.Pipe()
  
// 启用一个例程进行读取
  
go func() {
  
buf := make([]byte, 5)
  
for n, err := 0, error(nil); err == nil; {
  
n, err = r.Read(buf)
  
fmt.Printf("读取:%d, %v, %s\n", n, err, buf[:n])
  
}
  
}()
  
// 主例程进行写入
  
n, err := w.Write([]byte("Hello World !"))
  
fmt.Printf("写入:%d, %v\n", n, err)
  

  
w.CloseWithError(errors.New("管道被写入端关闭"))
  
n, err = w.Write([]byte("Hello World !"))
  
fmt.Printf("写入:%d, %v\n", n, err)
  
time.Sleep(time.Second * 1)
  
}
  

  
------------------------------------------------------------
  

  

  

  




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-594238-1-1.html 上篇帖子: 某智播客java视频教程 下篇帖子: golang reflect
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表