zoukankan      html  css  js  c++  java
  • golang 中io包用法(一)

    本文转自Golove博客:http://www.cnblogs.com/golove/p/3276678.html   ,并在此基础上进行修改.


    io 包为I/O原语提供了基础的接口.它主要包装了这些原语的已有实现,如 os 包中的那些,抽象成函数性的共享公共接口,加上一些其它相关的原语。

    由于这些接口和原语以不同的实现包装了低级操作,因此除非另行通知,否则客户不应假定它们对于并行执行是安全的。

    在io包中最重要的是两个接口:Reader和Writer接口,首先来介绍这两个接口.

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

    Reader 接口包装了基本的 Read 方法。

    Read 将 len(p) 个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len(p))以及任何遇到的错误。即使 Read 返回的 n < len(p),它也会在调用过程中使用 p的全部作为暂存空间。若一些数据可用但不到 len(p) 个字节,Read 会照例返回可用的东西,而不是等待更多。

    当 Read 在成功读取 n > 0 个字节后遇到一个错误或 EOF 情况,它就会返回读取的字节数。它会从相同的调用中返回(非nil的)错误或从随后的调用中返回错误(和 n == 0)。这种一般情况的一个例子就是 Reader 在输入流结束时会返回一个非零的字节数,可能的返回不是 err == EOF 就是 err == nil。无论如何,下一个 Read 都应当返回 0, EOF。

    调用者应当总在考虑到错误 err 前处理 n > 0 的字节。这样做可以在读取一些字节,以及允许的 EOF 行为后正确地处理I/O错误。

    Read 的实现会阻止返回零字节的计数和一个 nil 错误,调用者应将这种情况视作空操作。

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

    Writer 接口包装了基本的 Write 方法。

    Write 将 len(p) 个字节从 p 中写入到基本数据流中。它返回从 p 中被写入的字节数n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 Write 返回的n < len(p),它就必须返回一个非nil的错误。Write 不能修改此切片的数据,即便它是临时的。


    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 类型(以 string 为基类型)
    type Ustr string
    
    // 实现 Ustr 类型的 Read 方法
    func (s Ustr) Read(p []byte) (n int, err error) {
    	i, ls, lp := 0, len(s), len(p)
    	for ; i < ls && i < lp; i++ {
    		// 将小写字母转换为大写字母,然后写入 p 中
    		if s[i] >= 'a' && s[i] <= 'z' {
    			p[i] = s[i] + 'A' - 'a'
    		} else {
    			p[i] = s[i]
    		}
    	}
    	// 根据读取的字节数设置返回值
    	switch i {
    	case lp:
    		return i, nil
    	case ls:
    		return i, io.EOF
    	default:
    		return i, errors.New("Read Fail")
    	}
    }

      接下来,我们就可以用 ReadFull 方法读取 Ustr 对象的数据了:
    func main() {
    	us := Ustr("Hello World!")     // 创建 Ustr 对象 us
    	buf := make([]byte, 32)        // 创建缓冲区 buf
    	n, err := io.ReadFull(us, buf) // 将 us 中的数据读取到 buf 中
    	fmt.Printf("%s
    ", buf)        // 显示 buf 中的内容
    	// HELLO WORLD!
    	fmt.Println(n, err) // 显示返回值
    	// 12 unexpected EOF
    }
    

      我们很快就实现了 Reader 的要求,这个 Reader 就是一个接口,接口就是一个标准,一个要求,一个规定,这个规定就是“要实现接口中的方法”。只要某个对象符合 Reader 接口的要求,那么这个对象就可以当作 Reader 接口来使用,就可以传递给 ReadFull 方法。

      所以,只要文件对象实现了 Read 方法,那么 ReadFull 就可以读取文件中的数据,只要网络对象实现了 Read 方法,ReadFull 就可以读取网络中的数据,只要数据库实现了 Read 方法,ReadFull 就可以读取数据库中的数据,只要磁盘对象实现了 Read 方法,ReadFull 就可以读磁盘中的数据,只要内存对象实现了 Read 方法,ReadFull 就可以读取内存中的数据,只要任何一个对象实现了 Read 方法,ReadFull 就可以读取该对象的数据。

      在 io 包中,定义了许多基本的接口类型,Go 语言的标准库中大量使用了这些接口(就像 ReadFull 一样使用它们),下面我们就来看一看都有哪些接口:

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

    // Reader 接口封装了基本的 Read 方法
    // Read 方法用于将对象的数据流读入到 p 中
    // 直到“p 被装满”或者“数据被读完”或者“数据读取出错”为止
    // 返回读取的字节数 n (0 <= n <= len(p)) 和读取过程中遇到的任何错误
    // 如果“p 被装满”,则 err 应该返回 nil
    // 如果“数据被读完”,则 err 应该返回 EOF
    // 如果“数据读取出错”,则 err 应该返回相应的错误信息
    // Reader 用来输出数据
    type Reader interface {
    	Read(p []byte) (n int, err error)
    }

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

    // Writer 接口封装了基本的 Write 方法
    // Write 方法用于将 p 中的数据写入到对象的数据流中
    // 返回写入的字节数 n (0 <= n <= len(p)) 和写入时遇到的任何错误
    // 如果 p 中的数据全部被写入,则 err 应该返回 nil
    // 如果 p 中的数据无法被全部写入,则 err 应该返回相应的错误信息
    // Writer 用来存入数据
    type Writer interface {
    	Write(p []byte) (n int, err error)
    }

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

    // Closer 接口封装了基本的 Close 方法
    // Close 一般用于关闭文件,关闭连接,关闭数据库等
    // Close 用来关闭数据
    type Closer interface {
    	Close() error
    }

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

    // Seeker 接口封装了基本的 Seek 方法
    // Seek 设置下一次读写操作的指针位置,每次的读写操作都是从指针位置开始的
    // whence 的含义:
    // 如果 whence 为 0:表示从数据的开头开始移动指针
    // 如果 whence 为 1:表示从数据的当前指针位置开始移动指针
    // 如果 whence 为 2:表示从数据的尾部开始移动指针
    // offset 是指针移动的偏移量
    // 返回移动后的指针位置和移动过程中遇到的任何错误
    // Seeker 用来移动数据的读写指针

    type Seeker interface {
    	Seek(offset int64, whence int) (ret int64, err error)
    }

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

    // 下面是这些接口的组合接口

    type ReadWriter interface {
    	Reader
    	Writer
    }
    
    type ReadSeeker interface {
    	Reader
    	Seeker
    }
    
    type WriteSeeker interface {
    	Writer
    	Seeker
    }
    
    type ReadWriteSeeker interface {
    	Reader
    	Writer
    	Seeker
    }
    
    type ReadCloser interface {
    	Reader
    	Closer
    }
    
    type WriteCloser interface {
    	Writer
    	Closer
    }
    
    type ReadWriteCloser interface {
    	Reader
    	Writer
    	Closer
    }


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

    // ReaderFrom 接口封装了基本的 ReadFrom 方法
    // ReadFrom 从 r 中读取数据到对象的数据流中
    // 直到 r 返回 EOF 或 r 出现读取错误为止
    // 返回值 n 是读取的字节数
    // 返回值 err 就是 r 的返回值 err
    // ReadFrom 用来读出 r 中的数据
    type ReaderFrom interface {
    	ReadFrom(r Reader) (n int64, err error)
    }
    

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

    // WriterTo 接口封装了基本的 WriteTo 方法
    // WriterTo 将对象的数据流写入到 w 中
    // 直到对象的数据流全部写入完毕或遇到写入错误为止
    // 返回值 n 是写入的字节数
    // 返回值 err 就是 w 的返回值 err
    // WriteTo 用来将数据写入 w 中
    type WriterTo interface {
    	WriteTo(w Writer) (n int64, err error)
    }

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

    // ReaderAt 接口封装了基本的 ReadAt 方法
    // ReadAt 从对象数据流的 off 处读出数据到 p 中
    // 忽略数据的读写指针,从数据的起始位置偏移 off 处开始读取
    // 如果对象的数据流只有部分可用,不足以填满 p
    // 则 ReadAt 将等待所有数据可用之后,继续向 p 中写入
    // 直到将 p 填满后再返回
    // 在这点上 ReadAt 要比 Read 更严格
    // 返回读取的字节数 n 和读取时遇到的错误
    // 如果 n < len(p),则需要返回一个 err 值来说明
    // 为什么没有将 p 填满(比如 EOF)
    // 如果 n = len(p),而且对象的数据没有全部读完,则
    // err 将返回 nil
    // 如果 n = len(p),而且对象的数据刚好全部读完,则
    // err 将返回 EOF 或者 nil(不确定)
    type ReaderAt interface {
    	ReadAt(p []byte, off int64) (n int, err error)
    }
    

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

    // WriterAt 接口封装了基本的 WriteAt 方法
    // WriteAt 将 p 中的数据写入到对象数据流的 off 处
    // 忽略数据的读写指针,从数据的起始位置偏移 off 处开始写入
    // 返回写入的字节数和写入时遇到的错误
    // 如果 n < len(p),则必须返回一个 err 值来说明
    // 为什么没有将 p 完全写入
    type WriterAt interface {
    	WriteAt(p []byte, off int64) (n int, err error)
    }
    

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

    // ByteReader 接口封装了基本的 ReadByte 方法
    // ReadByte 从对象的数据流中读取一个字节到 c 中
    // 如果对象的数据流中没有可读数据,则返回一个错误信息

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

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

    // ByteScanner 在 ByteReader 的基础上增加了一个 UnreadByte 方法
    // UnreadByte 用于撤消最后一次的 ReadByte 操作
    // 即将对象的读写指针移到上次 ReadByte 之前的位置
    // 如果上一次的操作不是 ReadByte,则 UnreadByte 返回一个错误信息
    type ByteScanner interface {
    ByteReader
    UnreadByte() error
    }

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

    // ByteWriter 接口封装了基本的 WriteByte 方法
    // WriteByte 将一个字节 c 写入到对象的数据流中
    // 返回写入过程中遇到的任何错误

    type ByteWriter interface {
    	WriteByte(c byte) error
    }

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

    // RuneReader 接口封装了基本的 ReadRune 方法
    // ReadRune 从对象的数据流中读取一个字符到 r 中
    // 如果对象的数据流中没有可读数据,则返回一个错误信息
    type RuneReader interface {
    	ReadRune() (r rune, size int, err error)
    }

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

    // RuneScanner 在 RuneReader 的基础上增加了一个 UnreadRune 方法
    // UnreadRune 用于撤消最后一次的 ReadRune 操作
    // 即将对象的读写指针移到上次 ReadRune 之前的位置
    // 如果上一次的操作不是 ReadRune,则 UnreadRune 返回一个错误信息
    type RuneScanner interface {
    	RuneReader
    	UnreadRune() error
    }

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

    // bytes.NewBuffer 实现了很多基本的接口,可以通过 bytes 包学习接口的实现
    func main() {
    	bb := bytes.NewBuffer([]byte("Hello World!"))
    	b := make([]byte, 32)
    
    	bb.Read(b)
    	fmt.Printf("%s
    ", b) // Hello World!
    
    	bb.WriteString("New Data!
    ")
    	bb.WriteTo(os.Stdout) // New Data!
    
    	bb.WriteString("Third Data!")
    	bb.ReadByte()
    	fmt.Println(bb.String()) // hird Data!
    	bb.UnreadByte()
    	fmt.Println(bb.String()) // Third Data!
    }

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

    // 下面是 io 包中的函数

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

    // WriteString 将字符串 s 写入到 w 中
    // 返回写入的字节数和写入过程中遇到的任何错误
    // 如果 w 实现了 WriteString 方法
    // 则调用 w 的 WriteString 方法将 s 写入 w 中
    // 否则,将 s 转换为 []byte
    // 然后调用 w.Write 方法将数据写入 w 中
    func WriteString(w Writer, s string) (n int, err error)
    func main() {
    	// os.Stdout 实现了 Writer 接口
    	io.WriteString(os.Stdout, "Hello World!")
    	// Hello World!
    }

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

    // ReadAtLeast 从 r 中读取数据到 buf 中,要求至少读取 min 个字节
    // 返回读取的字节数 n 和读取过程中遇到的任何错误
    // 如果 n < min,则 err 返回 ErrUnexpectedEOF
    // 如果 r 中无可读数据,则 err 返回 EOF
    // 如果 min 大于 len(buf),则 err 返回 ErrShortBuffer
    // 只有当 n >= min 时 err 才返回 nil
    func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

    func main() {
    	r := strings.NewReader("Hello World!")
    	b := make([]byte, 32)
    	n, err := io.ReadAtLeast(r, b, 20)
    	fmt.Printf("%s
    %d, %v", b, n, err)
    	// Hello World!
    	// 12, unexpected EOF
    }

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

    // ReadFull 的功能和 ReadAtLeast 一样,只不过 min = len(buf),其中要求最少读取的字节数目是len(buf),当r中数据少于len(buf)时便会报错
    func ReadFull(r Reader, buf []byte) (n int, err error)

    func main() {
    	r := strings.NewReader("Hello World!")
    	b := make([]byte, 32)
    	n, err := io.ReadFull(r, b)
    	fmt.Printf("%s
    %d, %v", b, n, err)
    	// Hello World!
    	// 12, unexpected EOF
    }

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

    // CopyN 从 src 中复制 n 个字节的数据到 dst 中
    // 它返回复制的字节数 written 和复制过程中遇到的任何错误
    // 只有当 written = n 时,err 才返回 nil
    // 如果 dst 实现了 ReadFrom 方法,则调用 ReadFrom 来执行复制操作
    func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
    func main() {
    	r := strings.NewReader("Hello World!")
    	n, err := io.CopyN(os.Stdout, r, 20)
    	fmt.Printf("
    %d, %v", n, err)
    	// Hello World!
    	// 12, EOF
    }

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

    // Copy 从 src 中复制数据到 dst 中,直到所有数据复制完毕
    // 返回复制过程中遇到的任何错误
    // 如果数据复制完毕,则 err 返回 nil,而不是 EOF
    // 如果 dst 实现了 ReadeFrom 方法,则调用 dst.ReadeFrom(src) 复制数据
    // 如果 src 实现了 WriteTo 方法,则调用 src.WriteTo(dst) 复制数据
    func Copy(dst Writer, src Reader) (written int64, err error)

    func main() {
    	r := strings.NewReader("Hello World!")
    	n, err := io.Copy(os.Stdout, r)
    	fmt.Printf("
    %d, %v", n, err)
    	// Hello World!
    	// 12, <nil>
    }

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

    // LimitReader 覆盖了 r 的 Read 方法
    // 使 r 只能读取 n 个字节的数据,读取完毕后返回 EOF
    func LimitReader(r Reader, n int64) Reader

    // LimitedReader 结构用来实现 LimitReader 的功能
    type LimitedReader struct

    func main() {
    	r := strings.NewReader("Hello World!")
    	lr := io.LimitReader(r, 5)
    	n, err := io.CopyN(os.Stdout, lr, 20)
    	fmt.Printf("
    %d, %v", n, err)
    	// Hello
    	// 5, EOF
    }

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

    // NewSectionReader 封装 r,并返回 SectionReader 类型的对象
    // 使 r 只能从 off 的位置读取 n 个字节的数据,读取完毕后返回 EOF
    func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader

    // SectionReader 结构用来实现 NewSectionReader 的功能
    // SectionReader 实现了 Read、Seek、ReadAt、Size 方法
    type SectionReader struct

    // Size 返回 s 中被限制读取的字节数
    func (s *SectionReader) Size()

    func main() {
    	r := strings.NewReader("Hello World!")
    	sr := io.NewSectionReader(r, 0, 5)
    	n, err := io.CopyN(os.Stdout, sr, 20)
    	fmt.Printf("
    %d, %v", n, err)
    	fmt.Printf("
    %d", sr.Size())
    	// World
    	// 5, EOF
    	// 5
    }

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

    // TeeReader 覆盖了 r 的 Read 方法
    // 使 r 在读取数据的同时,自动向 w 中写入数据
    // 所有写入时遇到的错误都被作为 err 返回值
    func TeeReader(r Reader, w Writer) Reader
    func main() {
    	r := strings.NewReader("Hello World!")
    	tr := io.TeeReader(r, os.Stdout)
    	b := make([]byte, 32)
    	tr.Read(b)
    	// World World!
    }

  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/msnsj/p/4242598.html
Copyright © 2011-2022 走看看