标准库之input&output

1、基本的io接口

  在 io 包中最重要的是两个接口:Reader 和 Writer 接口。

  1.1Reader接口

Reader 接口的定义如下:

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

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

当 Read 在成功读取 n > 0 个字节后遇到一个错误或 EOF (end-of-file),它会返回读取的字节数。它可能会同时在本次的调用中返回一个non-nil错误,或在下一次的调用中返回这个错误(且 n 为 0)。 一般情况下, Reader会返回一个非0字节数n, 若 n = len(p) 个字节从输入源的结尾处由 Read 返回,Read可能返回 err == EOF 或者 err == nil。并且之后的 Read() 都应该返回 (n:0, err:EOF)。

调用者在考虑错误之前应当首先处理返回的数据。这样做可以正确地处理在读取一些字节后产生的 I/O 错误,同时允许EOF的出现。

场景举例:

func ReadFrom(reader io.Reader, num int) ([]byte, error) {
    p := make([]byte, num)
    n, err := reader.Read(p)
    if n > 0 {
        return p[:n], nil
    }
    return p, err
}

main(){
    // 从标准输入读取
    data, err = ReadFrom(os.Stdin, 11)

    // 从普通文件读取,其中 file 是 os.File 的实例
    data, err = ReadFrom(file, 9)

    // 从字符串读取
    data, err = ReadFrom(strings.NewReader("from string"), 12)
}

1.2Writer接口

Writer 接口的定义如下:

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

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

场景举例:

//在使用 Go 语言进行 Web 开发时,http.ResponseWriter 是最基本的类型之一,它本身是一个 Interface 类,原型如下:
type ResponseWriter interface { Header() Header Write([]byte) (int, error) WriteHeader(int) }
//直接调用 Write() 写入一串 []byte func helloHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") w.Write([]byte("Hello World")) return } func main() { http.HandleFunc("/", helloHandler) http.ListenAndServe(":8080", nil) }

1.3实现了 io.Reader 接口或 io.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: 抽象成带缓冲的流读取(比如按行读写)

2、ReaderAt 和 WriterAt 接口

2.1ReaderAt 接口

ReaderAt 接口的定义如下:
type ReaderAt interface {
    ReadAt(p []byte, off int64) (n int, err error)
}

ReadAt 从基本输入源的偏移量 off 处开始,将 len(p) 个字节读取到 p 中。它返回读取的字节数 n(0 <= n <= len(p))以及任何遇到的错误。

当 ReadAt 返回的 n < len(p) 时,它就会返回一个 非nil 的错误来解释 为什么没有返回更多的字节。在这一点上,ReadAt 比 Read 更严格。

即使 ReadAt 返回的 n < len(p),它也会在调用过程中使用 p 的全部作为暂存空间。若可读取的数据不到 len(p) 字节,ReadAt 就会阻塞,直到所有数据都可用或一个错误发生。 在这一点上 ReadAt 不同于 Read。

若 n = len(p) 个字节从输入源的结尾处由 ReadAt 返回,Read可能返回 err == EOF 或者 err == nil

若 ReadAt 携带一个偏移量从输入源读取,ReadAt 应当既不影响偏移量也不被它所影响。

可对相同的输入源并行执行 ReadAt 调用。

场景举例:

reader := strings.NewReader("Go语言中文网")
p := make([]byte, 6)
n, err := reader.ReadAt(p, 2)
if err != nil {
    panic(err)
}
fmt.Printf("%s, %d\n", p, n)

2.2WriterAt 接口

WriterAt 接口的定义如下:
type WriterAt interface {
    WriteAt(p []byte, off int64) (n int, err error)
}

WriteAt 从 p 中将 len(p) 个字节写入到偏移量 off 处的基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 WriteAt 返回的 n < len(p),它就必须返回一个 非nil 的错误。

若 WriteAt 携带一个偏移量写入到目标中,WriteAt 应当既不影响偏移量也不被它所影响。

若被写区域没有重叠,可对相同的目标并行执行 WriteAt 调用。

场景举例:

file, err := os.Create("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
file.WriteString("Golang中文社区——这里是多余")
n, err := file.WriteAt([]byte("Go语言中文网"), 24)
if err != nil {
    panic(err)
}
fmt.Println(n)

3、ReaderFrom 和 WriterTo 接口

3.1ReaderFrom 接口

ReaderFrom 的定义如下:

type ReaderFrom interface {
    ReadFrom(r Reader) (n int64, err error)
}

ReadFrom 从 r 中读取数据,直到 EOF 或发生错误。其返回值 n 为读取的字节数。除 io.EOF 之外,在读取过程中遇到的任何错误也将被返回。

如果 ReaderFrom 可用,Copy 函数就会使用它。

ReadFrom 方法不会返回 err == EOF。

场景举例:

//将文件中的数据全部读取(显示在标准输出)
file, err := os.Open("writeAt.txt")
if err != nil {
    panic(err)
}
defer file.Close()
writer := bufio.NewWriter(os.Stdout)
writer.ReadFrom(file)
writer.Flush()
 

3.2WriterTo接口

WriterTo的定义如下:
type WriterTo interface {
    WriteTo(w Writer) (n int64, err error)
}

WriteTo 将数据写入 w 中,直到没有数据可写或发生错误。其返回值 n 为写入的字节数。 在写入过程中遇到的任何错误也将被返回。

如果 WriterTo 可用,Copy 函数就会使用它。

场景举例:

//将一段文本输出到标准输出
reader := bytes.NewReader([]byte("Go语言中文网"))
reader.WriteTo(os.Stdout)

 

4、Seeker 接口

接口定义如下:

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

  Seek 设置下一次 Read 或 Write 的偏移量为 offset,它的解释取决于 whence: 0 表示相对于文件的起始处,1 表示相对于当前的偏移,而 2 表示相对于其结尾处。 Seek 返回新的偏移量和一个错误,如果有的话。

场景举例:

//获取倒数第二个字符
reader := strings.NewReader("Go语言中文网")
reader.Seek(-6, io.SeekEnd)
r, _, _ := reader.ReadRune()
fmt.Printf("%c\n", r)

 

5、Closer接口

接口定义如下:
type Closer interface {
    Close() error
}

该接口比较简单,只有一个 Close() 方法,用于关闭数据流。

文件 (os.File)、归档(压缩包)、数据库连接、Socket 等需要手动关闭的资源都实现了 Closer 接口。

 
 
 
 

 

posted @ 2022-05-24 15:28  ☞@_@  阅读(100)  评论(0编辑  收藏  举报