golang 从 io.Reader 读取数据

io.Reader

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

Reader接口用于包装基本的读取方法。

Read方法读取len(p)字节数据写入p。它返回写入的字节数和遇到的任何错误。即使Read方法返回值n < len(p),本方法在被调用时仍可能使用p的全部长度作为暂存空间。如果有部分可用数据,但不够len(p)字节,Read按惯例会返回可以读取到的数据,而不是等待更多数据。

当Read在读取n > 0个字节后遭遇错误或者到达文件结尾时,会返回读取的字节数。它可能会在该次调用返回一个非nil的错误,或者在下一次调用时返回0和该错误。一个常见的例子,Reader接口会在输入流的结尾返回非0的字节数,返回值err == EOF或err == nil。但不管怎样,下一次Read调用必然返回(0, EOF)。调用者应该总是先处理读取的n > 0字节再处理错误值。这么做可以正确的处理发生在读取部分数据后的I/O错误,也能正确处理EOF事件。

如果Read的某个实现返回0字节数和nil错误值,表示被阻碍;调用者应该将这种情况视为未进行操作。

net.Conn 中读取数据为例

使用TCP连接访问某个网站,采用HTTP 1.0的协议,让TCP连接保持短连接,读取完response之后连接会关闭,这样就模拟了io.EOF的错误

1
2
3
4
5
6
7
8
conn, err := net.Dial("tcp", "rpcx.site:80")
if err != nil {
    fmt.Println("dial error:", err)
    return
}
defer conn.Close()
// 发送请求, http 1.0 协议
fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")

io.Reader.Read

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    // 读取response
    var sb strings.Builder
    buf := make([]byte, 256)
    for {
        n, err := conn.Read(buf)
        if err != nil {
            if err != io.EOF {
                fmt.Println("read error:", err)
            }
            break
        }
        sb.Write(buf[:n])
    }
    // 显示结果
    fmt.Println("response:", sb.String())
    fmt.Println("total response size:", sb.Len())

io.Copy

1
2
3
4
5
6
7
8
9
    // 读取response
    var sb strings.Builder
    _, err = io.Copy(&sb, conn)
    if err != nil {
        fmt.Println("read error:", err)
    }
    // 显示结果
    fmt.Println("response:", sb.String())
    fmt.Println("total response size:", sb.Len())

ioutil.ReadAll

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    // 读取response
    data, err := ioutil.ReadAll(conn)
    if err != nil {
        if err != io.EOF {
            fmt.Println("read error:", err)
        }
        panic(err)
    }
    // 显示结果
    fmt.Println("response:", string(data))
    fmt.Println("total response size:", len(data))

io.ReadFull

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    // 读取response
    var sb strings.Builder
    buf := make([]byte, 256)
    for {
        n, err := io.ReadFull(conn, buf)
        if err != nil {
            if err != io.EOF && err != io.ErrUnexpectedEOF {
                fmt.Println("read error:", err)
            }
            break
        }
        sb.Write(buf[:n])
    }
    // 显示结果
    fmt.Println("response:", sb.String())
    fmt.Println("total response size:", sb.Len())

io.ReadAtLeast

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
    // 读取response
    var sb strings.Builder
    buf := make([]byte, 379)
    for {
        n, err := io.ReadAtLeast(conn, buf, 379)
        if err != nil {
            if err != io.EOF && err != io.ErrUnexpectedEOF {
                fmt.Println("read error:", err)
            }
            break
        }
        sb.Write(buf[:n])
    }
    // 显示结果
    fmt.Println("response:", sb.String())
    fmt.Println("total response size:", sb.Len())

io.LimitReader

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    // 读取response
    var sb strings.Builder
    buf := make([]byte, 379)
    rr := io.LimitReader(conn, 102400)
    for {
        n, err := io.ReadAtLeast(rr, buf, 379)
        if err != nil {
            if err != io.EOF && err != io.ErrUnexpectedEOF {
                fmt.Println("read error:", err)
            }
            break
        }
        sb.Write(buf[:n])
    }
    // 显示结果
    fmt.Println("response:", sb.String())
    fmt.Println("total response size:", sb.Len())

bufio.Read

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    // 读取response
    reader := bufio.NewReader(conn)
    buf := make([]byte, 379)
    n, err := reader.Read(buf)
    if err != nil {
        if err != io.EOF {
            fmt.Println("read error:", err)
        }
        panic(err)
    }
    // 显示结果
    fmt.Println("response:", string(buf[:n]))
    fmt.Println("total response size:", len(buf[:n]))

参考